Compare commits
16 Commits
Author | SHA1 | Date | |
---|---|---|---|
0551c0bb0b | |||
3ffd0adc21 | |||
edbb207735 | |||
f8ee5d20f4 | |||
a103364f1a | |||
56e6160e6a | |||
360462287f | |||
e8a141a000 | |||
fffff4973e | |||
ba3d392328 | |||
1ccd2009ee | |||
28f964a3e6 | |||
3b622984bf | |||
1cd39ad061 | |||
dcc9d642aa | |||
f3703c634e |
@ -1 +1,4 @@
|
|||||||
.git*
|
.git*
|
||||||
|
__pycache__
|
||||||
|
*.egg-info
|
||||||
|
build
|
||||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -222,5 +222,5 @@ cython_debug/
|
|||||||
|
|
||||||
# Other
|
# Other
|
||||||
/dev.py
|
/dev.py
|
||||||
/*.db
|
*.db
|
||||||
/*.db.*
|
*.db.*
|
||||||
|
56
Dockerfile
56
Dockerfile
@ -1,41 +1,71 @@
|
|||||||
# syntax=docker/dockerfile:1
|
# syntax=docker/dockerfile:1
|
||||||
FROM python:3.10
|
|
||||||
|
FROM python:3.10 as compile-sphinx5.3.0-base
|
||||||
|
|
||||||
RUN apt-get update
|
RUN apt-get update
|
||||||
RUN apt-get install -y python3-sphinx node.js npm
|
RUN apt-get install -y python3-sphinx
|
||||||
RUN npm install -g http-server
|
RUN pip install Sphinx==5.3.0 pydata-sphinx-theme==0.12.0
|
||||||
RUN pip install pydata-sphinx-theme
|
|
||||||
WORKDIR /app/
|
WORKDIR /app/
|
||||||
RUN pip install git+https://gitea.parrrate.ru/PTV/rainbowadn.git@e9fba7b064902ceedee0dd5578cb47030665a6aa
|
RUN pip install git+https://gitea.parrrate.ru/PTV/rainbowadn.git@e9fba7b064902ceedee0dd5578cb47030665a6aa
|
||||||
|
|
||||||
RUN mkdir /app/docs/
|
RUN mkdir /app/docs/
|
||||||
RUN mkdir /app/docs/build/
|
|
||||||
RUN mkdir /app/docs/build/html/
|
|
||||||
|
FROM compile-sphinx5.3.0-base as compile-legacy
|
||||||
|
|
||||||
WORKDIR /app/legacy/
|
WORKDIR /app/legacy/
|
||||||
RUN git clone --branch 1.0 https://gitea.parrrate.ru/PTV/ptvp35.git
|
RUN git clone --branch 1.0 https://gitea.parrrate.ru/PTV/ptvp35.git
|
||||||
WORKDIR /app/legacy/ptvp35/
|
WORKDIR /app/legacy/ptvp35/
|
||||||
|
|
||||||
|
|
||||||
|
FROM compile-legacy as compile-1.0
|
||||||
|
|
||||||
RUN python traced_example.py > traced_example.txt
|
RUN python traced_example.py > traced_example.txt
|
||||||
RUN python traced_example.py all > traced_example_all.txt
|
RUN python traced_example.py all > traced_example_all.txt
|
||||||
RUN cp -r docs/source/ ./source/
|
RUN cp -r docs/source/ ./source/
|
||||||
RUN cp docs/Makefile ./Makefile
|
RUN cp docs/Makefile ./Makefile
|
||||||
RUN make html
|
RUN make html
|
||||||
RUN cp -r /app/legacy/ptvp35/build/html/ /app/docs/build/html/1.0/
|
|
||||||
RUN git reset --hard
|
|
||||||
|
FROM compile-legacy as compile-1.1rc0
|
||||||
|
|
||||||
RUN git fetch && git checkout 1.1rc0
|
RUN git fetch && git checkout 1.1rc0
|
||||||
WORKDIR /app/legacy/ptvp35/docs/
|
WORKDIR /app/legacy/ptvp35/docs/
|
||||||
RUN make html
|
RUN make html
|
||||||
RUN cp -r /app/legacy/ptvp35/docs/build/html/ /app/docs/build/html/1.1rc0/
|
|
||||||
RUN rm -r /app/legacy/ptvp35/docs/build/
|
|
||||||
WORKDIR /app/legacy/ptvp35/
|
|
||||||
|
|
||||||
WORKDIR /app/
|
|
||||||
|
FROM compile-legacy as compile-1.1rc2
|
||||||
|
|
||||||
|
RUN git fetch && git checkout 1.1rc2
|
||||||
|
WORKDIR /app/legacy/ptvp35/docs/
|
||||||
|
RUN make html
|
||||||
|
|
||||||
|
|
||||||
|
FROM compile-legacy as compile-1.1.0
|
||||||
|
|
||||||
|
RUN git fetch && git checkout 1.1.0
|
||||||
|
WORKDIR /app/legacy/ptvp35/docs/
|
||||||
|
RUN make html
|
||||||
|
|
||||||
|
|
||||||
|
FROM compile-sphinx5.3.0-base as compile-latest
|
||||||
|
|
||||||
COPY docs/Makefile docs/Makefile
|
COPY docs/Makefile docs/Makefile
|
||||||
COPY setup.py setup.py
|
COPY setup.py setup.py
|
||||||
COPY traced_example.py traced_example.py
|
COPY docs/scripts docs/scripts
|
||||||
COPY ptvp35 ptvp35
|
COPY ptvp35 ptvp35
|
||||||
COPY docs/source docs/source
|
COPY docs/source docs/source
|
||||||
WORKDIR /app/docs/
|
WORKDIR /app/docs/
|
||||||
RUN make html
|
RUN make html
|
||||||
|
|
||||||
|
|
||||||
|
FROM node:19
|
||||||
|
|
||||||
|
RUN npm install -g http-server
|
||||||
WORKDIR /app/docs/build/html/
|
WORKDIR /app/docs/build/html/
|
||||||
|
COPY --from=compile-1.0 /app/legacy/ptvp35/build/html/ /app/docs/build/html/1.0/
|
||||||
|
COPY --from=compile-1.1rc0 /app/legacy/ptvp35/docs/build/html/ /app/docs/build/html/1.1rc0/
|
||||||
|
COPY --from=compile-1.1rc2 /app/legacy/ptvp35/docs/build/html/ /app/docs/build/html/1.1rc2/
|
||||||
|
COPY --from=compile-1.1.0 /app/legacy/ptvp35/docs/build/html/ /app/docs/build/html/1.1.0/
|
||||||
|
COPY --from=compile-latest /app/docs/build/html/ /app/docs/build/html/
|
||||||
CMD [ "http-server", "-p", "80" ]
|
CMD [ "http-server", "-p", "80" ]
|
||||||
|
@ -17,6 +17,6 @@ help:
|
|||||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||||
%: Makefile
|
%: Makefile
|
||||||
python ../traced_example.py > ../traced_example.txt
|
python scripts/traced_example.py > scripts/traced_example.txt
|
||||||
python ../traced_example.py all > ../traced_example_all.txt
|
python scripts/traced_example.py all > scripts/traced_example_all.txt
|
||||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||||
|
320
docs/scripts/traced_example.py
Normal file
320
docs/scripts/traced_example.py
Normal file
@ -0,0 +1,320 @@
|
|||||||
|
import asyncio
|
||||||
|
import pathlib
|
||||||
|
import sys
|
||||||
|
import threading
|
||||||
|
from contextlib import ExitStack
|
||||||
|
|
||||||
|
from rainbowadn.instrument import Instrumentation
|
||||||
|
|
||||||
|
try:
|
||||||
|
sys.path.append(str((pathlib.Path(__file__).parent / "../..").absolute()))
|
||||||
|
from ptvp35 import DbConnection, DbFactory, KVJson
|
||||||
|
from ptvp35.instrumentation import InstrumentDiskWrites
|
||||||
|
except:
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
async def aprint(*args, **kwargs):
|
||||||
|
print(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class LogWrites(InstrumentDiskWrites):
|
||||||
|
def __init__(self, /):
|
||||||
|
super().__init__()
|
||||||
|
self.loop = asyncio.get_running_loop()
|
||||||
|
|
||||||
|
def on_write(self, line: str, /) -> None:
|
||||||
|
asyncio.run_coroutine_threadsafe(aprint(f"{self.methodname}[{line}]"), self.loop).result()
|
||||||
|
|
||||||
|
|
||||||
|
class LogEE(Instrumentation):
|
||||||
|
def __init__(self, target, methodname: str):
|
||||||
|
super().__init__(target, methodname)
|
||||||
|
self.loop = asyncio.get_running_loop()
|
||||||
|
|
||||||
|
def _target_id(self) -> str:
|
||||||
|
name = self.target.__name__ if hasattr(self.target, "__name__") else self.target.__class__.__name__
|
||||||
|
return f"{name}.{self.methodname}"
|
||||||
|
|
||||||
|
def _print(self, thread, *args) -> None:
|
||||||
|
print(thread, self._target_id(), *args, sep="\t")
|
||||||
|
|
||||||
|
async def aprint(self, thread, *args) -> None:
|
||||||
|
self._print(thread, *args)
|
||||||
|
|
||||||
|
def print(self, *args) -> None:
|
||||||
|
if (ct := threading.current_thread()) is threading.main_thread():
|
||||||
|
self._print("main", *args)
|
||||||
|
else:
|
||||||
|
asyncio.run_coroutine_threadsafe(self.aprint("aux", *args), self.loop).result()
|
||||||
|
|
||||||
|
def instrument(self, method, *args, **kwargs):
|
||||||
|
self.print("enter")
|
||||||
|
try:
|
||||||
|
result = method(*args, **kwargs)
|
||||||
|
except:
|
||||||
|
self.print("error")
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
self.print("exit")
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
class ALogEE(LogEE):
|
||||||
|
async def instrument(self, method, *args, **kwargs):
|
||||||
|
self._print("aio", "enter")
|
||||||
|
try:
|
||||||
|
result = await method(*args, **kwargs)
|
||||||
|
except:
|
||||||
|
self._print("aio", "error")
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
self._print("aio", "exit")
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
async def transaction_test(db: DbConnection):
|
||||||
|
def logdb(*args):
|
||||||
|
if args:
|
||||||
|
args = (
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
"@",
|
||||||
|
) + args
|
||||||
|
print(db.get("test", "0"), *args, sep="\t")
|
||||||
|
|
||||||
|
def logstate(*args):
|
||||||
|
if args:
|
||||||
|
args = ("@",) + args
|
||||||
|
print(db.get("test", "0"), "|", state.get("test", "0"), *args, sep="\t")
|
||||||
|
|
||||||
|
logdb("empty db")
|
||||||
|
db.set_nowait("test", "1")
|
||||||
|
logdb("after set_nowait")
|
||||||
|
await db.set("test", "2")
|
||||||
|
logdb("after set")
|
||||||
|
try:
|
||||||
|
async with db.transaction() as state:
|
||||||
|
logstate("empty transaction")
|
||||||
|
state.set_nowait("test", "3")
|
||||||
|
logstate("after transaction.set_nowait")
|
||||||
|
state.submit()
|
||||||
|
logstate("after transaction.submit")
|
||||||
|
await state.commit()
|
||||||
|
logstate("after transaction.commit")
|
||||||
|
state.set_nowait("test", print) # will throw TypeError later
|
||||||
|
logstate()
|
||||||
|
except TypeError:
|
||||||
|
print("type error")
|
||||||
|
logdb("after transaction")
|
||||||
|
async with db.transaction() as state:
|
||||||
|
logstate()
|
||||||
|
state.set_nowait("test", "4")
|
||||||
|
logstate("before implicit transaction.commit")
|
||||||
|
logdb("after transaction with implicit commit")
|
||||||
|
with db.transaction() as state:
|
||||||
|
logstate()
|
||||||
|
state.set_nowait("test", "5")
|
||||||
|
logstate("before implicit transaction.submit")
|
||||||
|
logdb("after transaction with implicit submit")
|
||||||
|
|
||||||
|
|
||||||
|
def print_private_db_attrs(db: DbConnection):
|
||||||
|
if run_all:
|
||||||
|
for attr in dir(db):
|
||||||
|
if attr.startswith("_DbConnection") and hasattr(db, attr):
|
||||||
|
print(attr)
|
||||||
|
|
||||||
|
|
||||||
|
run_all = "all" in sys.argv
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
(path := pathlib.Path(__file__).parent / "trace_example.db").unlink(missing_ok=True)
|
||||||
|
|
||||||
|
with ExitStack() as es:
|
||||||
|
LogWrites().enter(es)
|
||||||
|
if run_all:
|
||||||
|
LogEE(__import__("ptvp35").Request, "__init__").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").Request, "waiting").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").Request, "set_result").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").Request, "set_exception").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35").Request, "wait").enter(es)
|
||||||
|
|
||||||
|
LogEE(__import__("ptvp35").LineRequest, "__init__").enter(es)
|
||||||
|
|
||||||
|
LogEE(__import__("ptvp35").KVFactory, "run").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").KVFactory, "_dbset").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").KVFactory, "dbset").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").KVFactory, "dbget").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").KVFactory, "filter_value").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").KVFactory, "request").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").KVFactory, "free").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").KVFactory, "io2db").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").KVFactory, "db2io").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").KVFactory, "path2db_sync").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").KVFactory, "db2path_sync").enter(es)
|
||||||
|
|
||||||
|
LogEE(__import__("ptvp35").KVRequest, "__init__").enter(es)
|
||||||
|
|
||||||
|
LogEE(__import__("ptvp35").KVJson, "line").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").KVJson, "_load_key").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").KVJson, "fromline").enter(es)
|
||||||
|
|
||||||
|
LogEE(__import__("ptvp35").TransactionRequest, "__init__").enter(es)
|
||||||
|
|
||||||
|
LogEE(__import__("ptvp35").DbParameters, "__init__").enter(es)
|
||||||
|
|
||||||
|
LogEE(__import__("ptvp35").VirtualConnection, "transaction").enter(es)
|
||||||
|
|
||||||
|
LogEE(__import__("ptvp35")._Loop, "__init__").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Loop, "create_future").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Loop, "loop").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Loop, "run_in_thread").enter(es)
|
||||||
|
|
||||||
|
LogEE(__import__("ptvp35")._Errors, "__init__").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Errors, "_save_sync").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35")._Errors, "_save").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Errors, "save_from_thread").enter(es)
|
||||||
|
|
||||||
|
LogEE(__import__("ptvp35")._File, "__init__").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._File, "path").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._File, "tell").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._File, "write_to_disk_sync").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._File, "open_sync").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._File, "close_sync").enter(es)
|
||||||
|
|
||||||
|
LogEE(__import__("ptvp35")._Backup, "__init__").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Backup, "file").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Backup, "kvfactory").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Backup, "_copy_sync").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Backup, "_recovery_unset_sync").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Backup, "_finish_recovery_sync").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Backup, "_recovery_set_sync").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Backup, "build_file_sync").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Backup, "_rebuild_file_sync").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Backup, "_reload_sync").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Backup, "run_in_thread").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35")._Backup, "_reload").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35")._Backup, "reload_if_oversized").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Backup, "load_mmdb_sync").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Backup, "uninitialize").enter(es)
|
||||||
|
|
||||||
|
LogEE(__import__("ptvp35")._Guard, "__init__").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Guard, "backup").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Guard, "_write_bytes_sync").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Guard, "_write_value_sync").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Guard, "_set_sync").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Guard, "_unset_sync").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Guard, "_read_bytes_sync").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Guard, "_read_value_sync").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Guard, "_truncate_sync").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Guard, "assure_sync").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Guard, "_file_truncate_sync").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Guard, "file_write_sync").enter(es)
|
||||||
|
|
||||||
|
LogEE(__import__("ptvp35")._ReceivingQueue, "__init__").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._ReceivingQueue, "submit").enter(es)
|
||||||
|
|
||||||
|
LogEE(__import__("ptvp35")._WriteableBuffer, "__init__").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._WriteableBuffer, "writeable").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._WriteableBuffer, "loop").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._WriteableBuffer, "_compressed").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._WriteableBuffer, "_commit_compressed_sync").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35")._WriteableBuffer, "_commit_compressed").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._WriteableBuffer, "_clear").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._WriteableBuffer, "_satisfy_future").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._WriteableBuffer, "_fail_future").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35")._WriteableBuffer, "_do_commit_buffer").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._WriteableBuffer, "_request_buffer").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35")._WriteableBuffer, "_commit").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35")._WriteableBuffer, "_commit_or_request_so").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35")._WriteableBuffer, "_write").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35")._WriteableBuffer, "_handle_request").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35")._WriteableBuffer, "_close").enter(es)
|
||||||
|
|
||||||
|
LogEE(__import__("ptvp35")._Memory, "__init__").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Memory, "_initialize_sync").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Memory, "_load_from_file_sync").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35")._Memory, "_load_from_file").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Memory, "_close_sync").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35")._Memory, "_close").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Memory, "_transaction_buffer").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Memory, "get").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._Memory, "set").enter(es)
|
||||||
|
|
||||||
|
LogEE(__import__("ptvp35")._QueueTask, "__init__").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35")._QueueTask, "_background_cycle").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35")._QueueTask, "_background_task").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35")._QueueTask, "close").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._QueueTask, "start").enter(es)
|
||||||
|
|
||||||
|
LogEE(__import__("ptvp35")._DbConnection, "__init__").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._DbConnection, "kvprotocol").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._DbConnection, "get").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35")._DbConnection, "set").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._DbConnection, "set_nowait").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35")._DbConnection, "_initialize_running").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35")._DbConnection, "_initialize").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35")._DbConnection, "create").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35")._DbConnection, "_close_running").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35")._DbConnection, "aclose").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35")._DbConnection, "commit_transaction").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._DbConnection, "submit_transaction").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._DbConnection, "submit_transaction_request").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35")._DbConnection, "commit").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._DbConnection, "loop").enter(es)
|
||||||
|
LogEE(__import__("ptvp35")._DbConnection, "transaction").enter(es)
|
||||||
|
|
||||||
|
LogEE(__import__("ptvp35").DbManager, "__init__").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35").DbManager, "__aenter__").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35").DbManager, "__aexit__").enter(es)
|
||||||
|
|
||||||
|
LogEE(__import__("ptvp35").Db, "__init__").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35").Db, "__aenter__").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35").Db, "__aexit__").enter(es)
|
||||||
|
|
||||||
|
LogEE(__import__("ptvp35").FutureContext, "__init__").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35").FutureContext, "__aenter__").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35").FutureContext, "__aexit__").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35").FutureContext, "wait").enter(es)
|
||||||
|
|
||||||
|
LogEE(__import__("ptvp35").TransactionView, "__init__").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").TransactionView, "future_context").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").TransactionView, "rollback").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").TransactionView, "illuminate").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35").TransactionView, "ailluminate").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").TransactionView, "fork").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35").TransactionView, "afork").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").TransactionView, "clear").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35").TransactionView, "aclear").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").TransactionView, "reset").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35").TransactionView, "areset").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").TransactionView, "get").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").TransactionView, "set_nowait").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").TransactionView, "_delta").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35").TransactionView, "commit").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").TransactionView, "submit").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").TransactionView, "_do_gather").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").TransactionView, "_reduce_future").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").TransactionView, "_gather").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35").TransactionView, "commit_transaction").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").TransactionView, "submit_transaction").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").TransactionView, "submit_transaction_request").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").TransactionView, "loop").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").TransactionView, "transaction").enter(es)
|
||||||
|
|
||||||
|
LogEE(__import__("ptvp35").Transaction, "__init__").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35").Transaction, "__aenter__").enter(es)
|
||||||
|
ALogEE(__import__("ptvp35").Transaction, "__aexit__").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").Transaction, "_clean").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").Transaction, "__enter__").enter(es)
|
||||||
|
LogEE(__import__("ptvp35").Transaction, "__exit__").enter(es)
|
||||||
|
async with DbFactory(path, kvfactory=KVJson()) as db:
|
||||||
|
await transaction_test(db)
|
||||||
|
print_private_db_attrs(db)
|
||||||
|
print_private_db_attrs(db)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
@ -9,34 +9,34 @@
|
|||||||
import os.path
|
import os.path
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
project = 'ptvp35'
|
project = "ptvp35"
|
||||||
copyright = '2022, PARRRATE TNV'
|
copyright = "2022, PARRRATE TNV"
|
||||||
author = 'PARRRATE TNV'
|
author = "PARRRATE TNV"
|
||||||
with open('../../setup.py') as f:
|
with open("../../setup.py") as f:
|
||||||
_src = f.read()
|
_src = f.read()
|
||||||
_src = _src[_src.index('version=\'') + 9:]
|
_src = _src[_src.index('version="') + 9 :]
|
||||||
_src = _src[:_src.index('\'')]
|
_src = _src[: _src.index('"')]
|
||||||
release = _src
|
release = _src
|
||||||
|
|
||||||
# -- General configuration ---------------------------------------------------
|
# -- General configuration ---------------------------------------------------
|
||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
||||||
|
|
||||||
extensions = [
|
extensions = [
|
||||||
'sphinx.ext.autodoc',
|
"sphinx.ext.autodoc",
|
||||||
]
|
]
|
||||||
|
|
||||||
templates_path = ['_templates']
|
templates_path = ["_templates"]
|
||||||
exclude_patterns = []
|
exclude_patterns = []
|
||||||
|
|
||||||
|
|
||||||
# -- Options for HTML output -------------------------------------------------
|
# -- Options for HTML output -------------------------------------------------
|
||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
|
||||||
|
|
||||||
html_theme = 'pydata_sphinx_theme'
|
html_theme = "pydata_sphinx_theme"
|
||||||
html_theme_options = {
|
html_theme_options = {
|
||||||
"navbar_center": [],
|
"navbar_center": [],
|
||||||
}
|
}
|
||||||
html_static_path = ['_static']
|
html_static_path = ["_static"]
|
||||||
|
|
||||||
|
|
||||||
sys.path.insert(0, os.path.abspath('../..'))
|
sys.path.insert(0, os.path.abspath("../.."))
|
||||||
|
@ -18,3 +18,5 @@ These apply both to the internal PARRRATE TNV team behind Persistence 5 and to e
|
|||||||
* Forking of the repository is encouraged.
|
* Forking of the repository is encouraged.
|
||||||
* Usage of the repository as a reference for custom data storage solutions is encouraged.
|
* Usage of the repository as a reference for custom data storage solutions is encouraged.
|
||||||
* Instrumentation code base is more open to direct code contributions.
|
* Instrumentation code base is more open to direct code contributions.
|
||||||
|
* Main way of instrumentation is code injection.
|
||||||
|
* Instrumentation on its own shouldn't require changes to the core code, even though instrumentation-allowing core code is preferred.
|
||||||
|
@ -1,12 +1,7 @@
|
|||||||
Historical notes
|
Historical notes
|
||||||
================
|
================
|
||||||
|
|
||||||
Persistence 1.
|
Persistence 1/2. CmbPrst.
|
||||||
--------------
|
|
||||||
|
|
||||||
* Used by CMB.
|
|
||||||
|
|
||||||
Persistence 2. CmbPrst.
|
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
* Internal storage of CMB.
|
* Internal storage of CMB.
|
||||||
@ -45,6 +40,8 @@ Persistence 5 1.1 (5.1.1).
|
|||||||
|
|
||||||
* Non-nightly support for transactions.
|
* Non-nightly support for transactions.
|
||||||
* Instrumentation support.
|
* Instrumentation support.
|
||||||
|
* Structural preparations for generic DBs.
|
||||||
|
* :code:`VDELETE`
|
||||||
|
|
||||||
Proposed future versions
|
Proposed future versions
|
||||||
========================
|
========================
|
||||||
|
@ -9,6 +9,7 @@ Memory-Resident DataBase for simple single-process asynchronous Python applicati
|
|||||||
|
|
||||||
motivation
|
motivation
|
||||||
usage
|
usage
|
||||||
|
structure
|
||||||
guarantees
|
guarantees
|
||||||
ordering
|
ordering
|
||||||
projects
|
projects
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
ptvp35
|
Modules
|
||||||
======
|
=======
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 4
|
:maxdepth: 4
|
||||||
|
@ -6,7 +6,7 @@ This page describes reasons for certain design decisions.
|
|||||||
General structure
|
General structure
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
* We're making a key-value database.
|
* A key-value database.
|
||||||
* Keys and values are python objects.
|
* Keys and values are python objects.
|
||||||
* While the DB is offline (after a correct shutdown), all its KVPs are stored as lines in one editable file.
|
* While the DB is offline (after a correct shutdown), all its KVPs are stored as lines in one editable file.
|
||||||
* DB should be able to survive powercut at any point (D in ACID).
|
* DB should be able to survive powercut at any point (D in ACID).
|
||||||
|
@ -4,17 +4,17 @@ Traced example of how ordering works in persistence5
|
|||||||
Source
|
Source
|
||||||
------
|
------
|
||||||
|
|
||||||
.. literalinclude :: ../../traced_example.py
|
.. literalinclude :: ../scripts/traced_example.py
|
||||||
:language: python3
|
:language: python3
|
||||||
|
|
||||||
Writes/reads log
|
Writes/reads log
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
.. literalinclude :: ../../traced_example.txt
|
.. literalinclude :: ../scripts/traced_example.txt
|
||||||
:language: plain
|
:language: plain
|
||||||
|
|
||||||
Everything log
|
Everything log
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
.. literalinclude :: ../../traced_example_all.txt
|
.. literalinclude :: ../scripts/traced_example_all.txt
|
||||||
:language: plain
|
:language: plain
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
ptvp35 package
|
ptvp35 (API Reference)
|
||||||
==============
|
======================
|
||||||
|
|
||||||
Module contents
|
Module contents
|
||||||
---------------
|
---------------
|
||||||
|
75
docs/source/structure.rst
Normal file
75
docs/source/structure.rst
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
Inner structure
|
||||||
|
===============
|
||||||
|
|
||||||
|
Main-Memory DataBase
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
* Represented via Python dictionary (:code:`dict`).
|
||||||
|
Future version may include more abstract options, i.e. :class:`~ptvp35.DbConnection` would be generic over :attr:`~ptvp35._DbConnection.__mmdb` field
|
||||||
|
* Keys and values are almost guaranteed to be serializable.
|
||||||
|
All KVPs loaded on :meth:`~ptvp35.DbManager.__aenter__` are re-serialized during file reload.
|
||||||
|
All KVPs added via submit-like methods are serialized before being added to the MMDB.
|
||||||
|
|
||||||
|
DataBase Stream File
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
* In current implementation, all database storage storage files are Newline-Delimited JSON streams (https://en.wikipedia.org/wiki/JSON_streaming#Newline-Delimited_JSON).
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{"key": ["tuple", "example"], "value": {"dict": "example"}}
|
||||||
|
{"key": 123, "value": null}
|
||||||
|
* During the runtime, the database uses 6 different files:
|
||||||
|
* `.db` Main file.
|
||||||
|
Should be the only non-error file after correct shutdown.
|
||||||
|
* `.db.backup` Backup file.
|
||||||
|
Generated when the main file is being rebuilt.
|
||||||
|
* `.db.recover` Flag file.
|
||||||
|
Indicates that backup file is valid and that main file's validity is undefined.
|
||||||
|
* `.db.truncate` Auxiliary file created on each write to main file.
|
||||||
|
Contains 16 bytes little-endian representation of up to how many characters the main file is valid.
|
||||||
|
* `.db.truncate_flag` Flag file.
|
||||||
|
Indicates that truncate file is valid and that main file's validity after the specified character count is undefined.
|
||||||
|
* `.db.error` Error log file.
|
||||||
|
In current implementation, it contains only the main file contents that got truncated on recovery.
|
||||||
|
* All storage file writes are :code:`fsync`'ed.
|
||||||
|
* :code:`pathlib.Path.write_bytes` usecase relies on synchronisation/file-creation ordering. That may get replaced in future versions.
|
||||||
|
|
||||||
|
Request Queue
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Transaction View (:class:`~ptvp35.TransactionView`)
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
Connection-like interface on top of another connection-like interface.
|
||||||
|
|
||||||
|
* Provides most of the same methods as :class:`~ptvp35.DbConnection`.
|
||||||
|
* From the common :class:`~ptvp35.VirtualConnection` interface/base class:
|
||||||
|
* :meth:`~ptvp35.TransactionView.get`
|
||||||
|
* :meth:`~ptvp35.TransactionView.commit_transaction`
|
||||||
|
* :meth:`~ptvp35.TransactionView.submit_transaction_request`
|
||||||
|
* :meth:`~ptvp35.TransactionView.loop`
|
||||||
|
* :meth:`~ptvp35.VirtualConnection.transaction` (default implementation)
|
||||||
|
* Extra common methods (:class:`~ptvp35.ExtendedVirtualConnection`):
|
||||||
|
* :meth:`~ptvp35.TransactionView.set_nowait`
|
||||||
|
* :meth:`~ptvp35.TransactionView.submit_transaction`
|
||||||
|
* :meth:`~ptvp35.TransactionView.commit`
|
||||||
|
* Does not have the the analogue for the :meth:`~ptvp35.DbInterface.set` method.
|
||||||
|
* The reason for that is :code:`set` method having semantics contradictory to transactions.
|
||||||
|
* The :code:`set` provides a way to set a *single* value and wait until it's committed.
|
||||||
|
* Transactions are meant for a more fine control.
|
||||||
|
* The equivalent would consist of using a subtransaction or of the following method calls:
|
||||||
|
* :meth:`~ptvp35.TransactionView.set_nowait` to set the value in :code:`__delta`.
|
||||||
|
* :meth:`~ptvp35.TransactionView.submit` to pass all the :code:`__delta` values.
|
||||||
|
* :meth:`~ptvp35.TransactionView.future_context` to get the context for that specific key.
|
||||||
|
* :meth:`~ptvp35.FutureContext.wait` to wait until that key is committed.
|
||||||
|
* :meth:`~ptvp35.TransactionView.illuminate` to clear :code:`__shadow` thus resetting the view to DB state.
|
||||||
|
|
||||||
|
Transaction (:class:`~ptvp35.Transaction`)
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
Manages a Transaction View.
|
||||||
|
|
||||||
|
* Creates and returns a Transaction View on :code:`__aenter__`/:code:`__enter__`.
|
||||||
|
* Submits changes on successful :code:`__exit__`.
|
||||||
|
* Commits changes on successful :code:`__aexit__`.
|
||||||
|
* Rolls back changes on unsuccessful :code:`__exit__`/:code:`__aexit__`.
|
@ -13,12 +13,10 @@ Default installation option is to use pip+git
|
|||||||
Basic functionality
|
Basic functionality
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
.. autoclass:: ptvp35.DbFactory
|
:class:`~ptvp35.DbFactory` class provides context management for database connections (:class:`~ptvp35.DbConnection`) via :code:`async with` statement.
|
||||||
|
The connection isn't just a "connection", it's also the MMDB itself, so **using two connections to one database is an undefined behaviour**.
|
||||||
:code:`DbFactory` class provides context management for database connections (:code:`DbConnection`) via :code:`async with` statement.
|
Also, that means that each connection start/shutdown is quite time expensive.
|
||||||
The connection isn't just a "connection", it's also the MMDB itself, so **using two connections to one database is an undefined behaviour**.
|
These two facts together tell that, if you intend on using the connection, you should probably wrap the main program in an :code:`async with` block.
|
||||||
Also, that means that each connection start/shutdown is quite time expensive.
|
|
||||||
These two facts together tell that, if you intend on using the connection, you should probably wrap the main program in an :code:`async with` block.
|
|
||||||
|
|
||||||
.. code-block:: python3
|
.. code-block:: python3
|
||||||
|
|
||||||
@ -62,26 +60,4 @@ Different ways to get/set a value:
|
|||||||
transaction.set_nowait('increment-5', value5 + 1)
|
transaction.set_nowait('increment-5', value5 + 1)
|
||||||
await connection.commit()
|
await connection.commit()
|
||||||
|
|
||||||
.. autoclass:: ptvp35.DbConnection
|
For common methods see: :class:`~ptvp35.AbstractDbConnection`
|
||||||
|
|
||||||
.. automethod:: get
|
|
||||||
|
|
||||||
this method is instant.
|
|
||||||
|
|
||||||
.. automethod:: set
|
|
||||||
|
|
||||||
this method may take time to run.
|
|
||||||
ordering may not be guaranteed (depends on event loop implementation).
|
|
||||||
|
|
||||||
.. automethod:: set_nowait
|
|
||||||
|
|
||||||
this method is instant.
|
|
||||||
ordering is guaranteed.
|
|
||||||
|
|
||||||
.. automethod:: commit
|
|
||||||
|
|
||||||
this method may take time to run.
|
|
||||||
respects the ordering of previously called :code:`set_nowait` methods.
|
|
||||||
will, under most circumstances, also execute later changes.
|
|
||||||
|
|
||||||
.. automethod:: transaction
|
|
||||||
|
1163
ptvp35/__init__.py
1163
ptvp35/__init__.py
File diff suppressed because it is too large
Load Diff
@ -1,12 +1,12 @@
|
|||||||
import ptvp35
|
import ptvp35
|
||||||
from rainbowadn.instrument import Instrumentation
|
from rainbowadn.instrument import Instrumentation
|
||||||
|
|
||||||
__all__ = ('InstrumentDiskWrites', 'NightlyInstrumentation')
|
__all__ = ("InstrumentDiskWrites",)
|
||||||
|
|
||||||
|
|
||||||
class InstrumentDiskWrites(Instrumentation):
|
class InstrumentDiskWrites(Instrumentation):
|
||||||
def __init__(self, /):
|
def __init__(self, /):
|
||||||
super().__init__(ptvp35.DbConnection, '_write_to_disk_sync')
|
super().__init__(ptvp35._File, "write_to_disk_sync")
|
||||||
|
|
||||||
def on_write(self, line: str, /) -> None:
|
def on_write(self, line: str, /) -> None:
|
||||||
pass
|
pass
|
||||||
@ -14,12 +14,3 @@ class InstrumentDiskWrites(Instrumentation):
|
|||||||
def instrument(self, method, db, line, /):
|
def instrument(self, method, db, line, /):
|
||||||
self.on_write(line)
|
self.on_write(line)
|
||||||
return method(db, line)
|
return method(db, line)
|
||||||
|
|
||||||
|
|
||||||
class NightlyInstrumentation(Instrumentation):
|
|
||||||
def __init__(self, target, methodname: str):
|
|
||||||
method = getattr(target, methodname)
|
|
||||||
if hasattr(method, '__non_nightly__'):
|
|
||||||
target = method
|
|
||||||
methodname = '__non_nightly__'
|
|
||||||
super().__init__(target, methodname)
|
|
||||||
|
16
setup.py
16
setup.py
@ -1,12 +1,12 @@
|
|||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='ptvp35',
|
name="ptvp35",
|
||||||
version='1.1rc2',
|
version="1.1.0",
|
||||||
packages=['ptvp35'],
|
packages=["ptvp35"],
|
||||||
url='https://gitea.ongoteam.net/PTV/ptvp35',
|
url="https://gitea.ongoteam.net/PTV/ptvp35",
|
||||||
license='MIT',
|
license="MIT",
|
||||||
author='PARRRATE TNV',
|
author="PARRRATE TNV",
|
||||||
author_email='',
|
author_email="",
|
||||||
description='',
|
description="",
|
||||||
)
|
)
|
||||||
|
23
test_delete.py
Normal file
23
test_delete.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import asyncio
|
||||||
|
import pathlib
|
||||||
|
|
||||||
|
from ptvp35 import VDELETE, DbFactory, KVJson
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
path = pathlib.Path("test_delete.db")
|
||||||
|
path.unlink(missing_ok=True)
|
||||||
|
async with DbFactory(path, kvfactory=KVJson()) as connection:
|
||||||
|
connection.set_nowait(0, 0)
|
||||||
|
print(connection.get(0, 1))
|
||||||
|
await connection.commit()
|
||||||
|
async with connection.transaction() as transaction:
|
||||||
|
print(transaction.get(0, 1))
|
||||||
|
transaction.set_nowait(0, VDELETE)
|
||||||
|
print(transaction.get(0, 1))
|
||||||
|
input()
|
||||||
|
print(connection.get(0, 1))
|
||||||
|
# path.unlink(missing_ok=True)
|
||||||
|
|
||||||
|
|
||||||
|
asyncio.run(main())
|
@ -1,286 +0,0 @@
|
|||||||
import asyncio
|
|
||||||
import pathlib
|
|
||||||
import sys
|
|
||||||
import threading
|
|
||||||
from contextlib import ExitStack
|
|
||||||
|
|
||||||
from ptvp35 import *
|
|
||||||
from ptvp35.instrumentation import *
|
|
||||||
|
|
||||||
|
|
||||||
async def aprint(*args, **kwargs):
|
|
||||||
print(*args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class LogWrites(InstrumentDiskWrites):
|
|
||||||
def __init__(self, /):
|
|
||||||
super().__init__()
|
|
||||||
self.loop = asyncio.get_running_loop()
|
|
||||||
|
|
||||||
def on_write(self, line: str, /) -> None:
|
|
||||||
asyncio.run_coroutine_threadsafe(
|
|
||||||
aprint(f'{self.methodname}[{line}]'), self.loop
|
|
||||||
).result()
|
|
||||||
|
|
||||||
|
|
||||||
class LogEE(NightlyInstrumentation):
|
|
||||||
def __init__(self, target, methodname: str):
|
|
||||||
super().__init__(target, methodname)
|
|
||||||
self.loop = asyncio.get_running_loop()
|
|
||||||
|
|
||||||
def _target_id(self) -> str:
|
|
||||||
name = (
|
|
||||||
self.target.__name__
|
|
||||||
if
|
|
||||||
hasattr(self.target, '__name__')
|
|
||||||
else
|
|
||||||
self.target.__class__.__name__
|
|
||||||
)
|
|
||||||
return f'{name}.{self.methodname}'
|
|
||||||
|
|
||||||
def _print(self, thread, *args) -> None:
|
|
||||||
print(
|
|
||||||
thread,
|
|
||||||
self._target_id(),
|
|
||||||
*args,
|
|
||||||
sep='\t'
|
|
||||||
)
|
|
||||||
|
|
||||||
async def aprint(self, thread, *args) -> None:
|
|
||||||
self._print(thread, *args)
|
|
||||||
|
|
||||||
def print(self, *args) -> None:
|
|
||||||
if (ct := threading.current_thread()) is threading.main_thread():
|
|
||||||
self._print('main', *args)
|
|
||||||
else:
|
|
||||||
asyncio.run_coroutine_threadsafe(
|
|
||||||
self.aprint('aux', *args), self.loop
|
|
||||||
).result()
|
|
||||||
|
|
||||||
def instrument(self, method, *args, **kwargs):
|
|
||||||
self.print('enter')
|
|
||||||
try:
|
|
||||||
result = method(*args, **kwargs)
|
|
||||||
except:
|
|
||||||
self.print('error')
|
|
||||||
raise
|
|
||||||
else:
|
|
||||||
self.print('exit')
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
class ALogEE(LogEE):
|
|
||||||
async def instrument(self, method, *args, **kwargs):
|
|
||||||
self._print('aio', 'enter')
|
|
||||||
try:
|
|
||||||
result = await method(*args, **kwargs)
|
|
||||||
except:
|
|
||||||
self._print('aio', 'error')
|
|
||||||
raise
|
|
||||||
else:
|
|
||||||
self._print('aio', 'exit')
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
async def transaction_test(db: DbConnection):
|
|
||||||
def logdb(*args):
|
|
||||||
if args:
|
|
||||||
args = (' ', ' ', '@',) + args
|
|
||||||
print(db.get('test', '0'), *args, sep='\t')
|
|
||||||
|
|
||||||
def logstate(*args):
|
|
||||||
if args:
|
|
||||||
args = ('@',) + args
|
|
||||||
print(db.get('test', '0'), '|', state.get('test', '0'), *args, sep='\t')
|
|
||||||
|
|
||||||
logdb('empty db')
|
|
||||||
db.set_nowait('test', '1')
|
|
||||||
logdb('after set_nowait')
|
|
||||||
await db.set('test', '2')
|
|
||||||
logdb('after set')
|
|
||||||
try:
|
|
||||||
async with db.transaction() as state:
|
|
||||||
logstate('empty transaction')
|
|
||||||
state.set_nowait('test', '3')
|
|
||||||
logstate('after transaction.set_nowait')
|
|
||||||
state.submit()
|
|
||||||
logstate('after transaction.submit')
|
|
||||||
await state.commit()
|
|
||||||
logstate('after transaction.commit')
|
|
||||||
state.set_nowait('test', print) # will throw TypeError later
|
|
||||||
logstate()
|
|
||||||
except TypeError:
|
|
||||||
print('type error')
|
|
||||||
logdb('after transaction')
|
|
||||||
async with db.transaction() as state:
|
|
||||||
logstate()
|
|
||||||
state.set_nowait('test', '4')
|
|
||||||
logstate('before implicit transaction.commit')
|
|
||||||
logdb('after transaction with implicit commit')
|
|
||||||
with db.transaction() as state:
|
|
||||||
logstate()
|
|
||||||
state.set_nowait('test', '5')
|
|
||||||
logstate('before implicit transaction.submit')
|
|
||||||
logdb('after transaction with implicit submit')
|
|
||||||
|
|
||||||
|
|
||||||
def print_private_db_attrs(db: DbConnection):
|
|
||||||
if run_all:
|
|
||||||
for attr in dir(db):
|
|
||||||
if attr.startswith('_DbConnection') and hasattr(db, attr):
|
|
||||||
print(attr)
|
|
||||||
|
|
||||||
|
|
||||||
run_all = 'all' in sys.argv
|
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
|
||||||
(path := pathlib.Path('dev.db')).unlink(missing_ok=True)
|
|
||||||
|
|
||||||
with ExitStack() as es:
|
|
||||||
LogWrites().enter(es)
|
|
||||||
if run_all:
|
|
||||||
LogEE(__import__('ptvp35').Request, '__init__').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').Request, 'waiting').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').Request, 'set_result').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').Request, 'set_exception').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').Request, 'wait').enter(es)
|
|
||||||
|
|
||||||
LogEE(__import__('ptvp35').LineRequest, '__init__').enter(es)
|
|
||||||
|
|
||||||
LogEE(__import__('ptvp35').KVFactory, 'run').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').KVFactory, 'request').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').KVFactory, 'free').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').KVFactory, 'io2db').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').KVFactory, 'db2io').enter(es)
|
|
||||||
|
|
||||||
LogEE(__import__('ptvp35').KVRequest, '__init__').enter(es)
|
|
||||||
|
|
||||||
LogEE(__import__('ptvp35').KVJson, 'line').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').KVJson, '_load_key').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').KVJson, 'fromline').enter(es)
|
|
||||||
|
|
||||||
LogEE(__import__('ptvp35').TransactionRequest, '__init__').enter(es)
|
|
||||||
|
|
||||||
LogEE(__import__('ptvp35').DbParametres, '__init__').enter(es)
|
|
||||||
|
|
||||||
LogEE(__import__('ptvp35').VirtualConnection, 'transaction').enter(es)
|
|
||||||
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '__init__').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_create_future').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_save_error_sync').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').DbConnection, '_save_error').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_queue_error').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_save_error_from_thread').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_path2db_sync').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_db2path_sync').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, 'get').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').DbConnection, 'set').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, 'set_nowait').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_clear_buffer').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_compress_buffer').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_commit_compressed_buffer_sync').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').DbConnection, '_commit_compressed_buffer').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_satisfy_buffer_future').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_fail_buffer_future').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').DbConnection, '_do_commit_buffer').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').DbConnection, '_commit_buffer').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_request_buffer').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').DbConnection, '_commit_buffer_or_request_so').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').DbConnection, '_write').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_truncation_set_sync').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_truncation_unset_sync').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_file_truncate_sync').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_truncation_target_sync').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_truncate_sync').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_assure_truncation_sync').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_write_to_disk_sync').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_file_write_sync').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').DbConnection, '_reload_if_oversized').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').DbConnection, '_handle_request').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').DbConnection, '_background_cycle').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').DbConnection, '_background_task').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_start_task').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_recovery_set_sync').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_recovery_unset_sync').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_copy_sync').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_finish_recovery_sync').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_build_file_sync').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_run_in_thread').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_rebuild_file_sync').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_file_open_sync').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_file_close_sync').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_reload_sync').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').DbConnection, '_reload').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_load_mmdb_sync').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_initialize_mmdb_sync').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_load_from_file_sync').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').DbConnection, '_load_from_file').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_initialize_queue').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').DbConnection, '_initialize_running').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').DbConnection, '_initialize').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').DbConnection, '_close_buffer').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').DbConnection, '_close_queue').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_close_mmdb_sync').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').DbConnection, '_close_mmdb').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').DbConnection, '_close_running').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').DbConnection, 'aclose').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, '_transaction_buffer').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').DbConnection, 'commit_transaction').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, 'submit_transaction').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, 'submit_transaction_request').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').DbConnection, 'commit').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, 'loop').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').DbConnection, 'transaction').enter(es)
|
|
||||||
|
|
||||||
LogEE(__import__('ptvp35').DbFactory, '__init__').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').DbFactory, '__aenter__').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').DbFactory, '__aexit__').enter(es)
|
|
||||||
|
|
||||||
LogEE(__import__('ptvp35').Db, '__init__').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').Db, '__aenter__').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').Db, '__aexit__').enter(es)
|
|
||||||
|
|
||||||
LogEE(__import__('ptvp35').FutureContext, '__init__').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').FutureContext, '__aenter__').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').FutureContext, '__aexit__').enter(es)
|
|
||||||
|
|
||||||
LogEE(__import__('ptvp35').TransactionView, '__init__').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').TransactionView, 'future_context').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').TransactionView, 'rollback').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').TransactionView, 'illuminate').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').TransactionView, 'ailluminate').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').TransactionView, 'fork').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').TransactionView, 'afork').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').TransactionView, 'clear').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').TransactionView, 'aclear').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').TransactionView, 'reset').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').TransactionView, 'areset').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').TransactionView, 'get').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').TransactionView, 'set_nowait').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').TransactionView, '_delta').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').TransactionView, 'commit').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').TransactionView, 'submit').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').TransactionView, '_do_gather').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').TransactionView, '_reduce_future').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').TransactionView, '_gather').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').TransactionView, 'commit_transaction').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').TransactionView, 'submit_transaction').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').TransactionView, 'submit_transaction_request').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').TransactionView, 'loop').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').TransactionView, 'transaction').enter(es)
|
|
||||||
|
|
||||||
LogEE(__import__('ptvp35').Transaction, '__init__').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').Transaction, '__aenter__').enter(es)
|
|
||||||
ALogEE(__import__('ptvp35').Transaction, '__aexit__').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').Transaction, '_clean').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').Transaction, '__enter__').enter(es)
|
|
||||||
LogEE(__import__('ptvp35').Transaction, '__exit__').enter(es)
|
|
||||||
async with DbFactory(path, kvfactory=KVJson()) as db:
|
|
||||||
await transaction_test(db)
|
|
||||||
print_private_db_attrs(db)
|
|
||||||
print_private_db_attrs(db)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
asyncio.run(main())
|
|
Loading…
Reference in New Issue
Block a user