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 :code:`__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.TransactionView.transaction` (default implementation) * Non-standard common methods: * :meth:`ptvp35.TransactionView.set_nowait` * :meth:`ptvp35.TransactionView.submit_transaction` * :meth:`ptvp35.TransactionView.commit` * Does not have the the analogue for the :meth:`ptvp35.DbConnection.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. * Transaction are meant for a more fine control. * The equivalent would consist of the three 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.commit` wait until all changes are commited. 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__`.