daodb


Namedaodb JSON
Version 0.0.6 PyPI version JSON
download
home_pagehttps://declassed.art/repository/daodb
SummaryDeclassed Append-Only Database
upload_time2023-03-18 19:32:52
maintainer
docs_urlNone
authorAXY
requires_python>=3.6
license
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            ======
DAO DB
======

Declassed Append-Only Database

---------
Example 1
---------

.. code:: python

    from daodb import DaoDB

    with DaoDB('test', 'w') as db:
        db.append(b'foo')
        db.append(b'bar')
        db.append(b'baz')
        for i, record in enumerate(db):
            print(i, record)

Result::

    0 b'foo'
    1 b'bar'
    2 b'baz'


---------
Example 2
---------

.. code:: python

    from daodb import JsonDaoDB

    with JsonDaoDB('test.json', 'w') as db:
        db.append({'foo': 'bar'})
        db.append({'bar': 'foo'})
        for i, record in enumerate(db):
            print(i, record)

Result::

    0 {'foo': 'bar'}
    1 {'bar': 'foo'}

-----------
Compression
-----------

Gzip and LZMA are included in the base package. LZ4, Brotli, and Snappy
depend on `lz4 <https://pypi.org/project/lz4/>`_, `brotli <https://pypi.org/project/Brotli/>`_,
and `python-snappy <https://pypi.org/project/python-snappy/>`_ packages respectively.

All DAO DB extensions are mix-ins. Here's how to define databases that store JSON with compression:

.. code:: python

    from daodb import DaoDB, GzipMixin, LzmaMixin
    from daodb.lz4 import Lz4Mixin
    from daodb.brotli import BrotliMixin
    from daodb.snappy import SnappyMixin

    class GzipDaoDB(JsonMixin, GzipMixin, DaoDB):
        pass

    class Lz4DaoDB(JsonMixin, Lz4Mixin, DaoDB):
        pass

    class LzmaDaoDB(JsonMixin, LzmaMixin, DaoDB):
        pass

    class BrotliDaoDB(JsonMixin, BrotliMixin, DaoDB):
        pass

    class SnappyDaoDB(JsonMixin, SnappyMixin, DaoDB):
        pass

------------------
Database structure
------------------

* data file
* index file

Index file contains positions of records except the first one which is always zero,
and the position for new record.
Thus, the number of items in the index file equals to the number of records.

Record id is implicit, it's the index of the record.
Thus, to get a record by id, read offsets from the index file and then read the record from data file.

---------
Algorithm
---------

Write:

* lock index file exclusively
* get position for the new record from the index file
* append new record to the data file
* write new size of data file to the index file
* release file lock

Read item by id:

* Given that id is the index of record, seek to id * 16 in the index file.
* Read the position of the record and the position of the next record from the index file, 16 bytes total.
* Read the record from the data file, the size of record is calculated as a difference between positions.

No lock is necessary for read operation.
That's because append is atomic and the data written to the index file (16 bytes)
will never be split across pages to make this bug take into effect: https://bugzilla.kernel.org/show_bug.cgi?id=55651



            

Raw data

            {
    "_id": null,
    "home_page": "https://declassed.art/repository/daodb",
    "name": "daodb",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.6",
    "maintainer_email": "",
    "keywords": "",
    "author": "AXY",
    "author_email": "axy@declassed.art",
    "download_url": "https://files.pythonhosted.org/packages/59/05/7b6e151341d9c5c36a58390a09ad962820dacfc2c8aa95e2b32c53c4a404/daodb-0.0.6.tar.gz",
    "platform": null,
    "description": "======\nDAO DB\n======\n\nDeclassed Append-Only Database\n\n---------\nExample 1\n---------\n\n.. code:: python\n\n    from daodb import DaoDB\n\n    with DaoDB('test', 'w') as db:\n        db.append(b'foo')\n        db.append(b'bar')\n        db.append(b'baz')\n        for i, record in enumerate(db):\n            print(i, record)\n\nResult::\n\n    0 b'foo'\n    1 b'bar'\n    2 b'baz'\n\n\n---------\nExample 2\n---------\n\n.. code:: python\n\n    from daodb import JsonDaoDB\n\n    with JsonDaoDB('test.json', 'w') as db:\n        db.append({'foo': 'bar'})\n        db.append({'bar': 'foo'})\n        for i, record in enumerate(db):\n            print(i, record)\n\nResult::\n\n    0 {'foo': 'bar'}\n    1 {'bar': 'foo'}\n\n-----------\nCompression\n-----------\n\nGzip and LZMA are included in the base package. LZ4, Brotli, and Snappy\ndepend on `lz4 <https://pypi.org/project/lz4/>`_, `brotli <https://pypi.org/project/Brotli/>`_,\nand `python-snappy <https://pypi.org/project/python-snappy/>`_ packages respectively.\n\nAll DAO DB extensions are mix-ins. Here's how to define databases that store JSON with compression:\n\n.. code:: python\n\n    from daodb import DaoDB, GzipMixin, LzmaMixin\n    from daodb.lz4 import Lz4Mixin\n    from daodb.brotli import BrotliMixin\n    from daodb.snappy import SnappyMixin\n\n    class GzipDaoDB(JsonMixin, GzipMixin, DaoDB):\n        pass\n\n    class Lz4DaoDB(JsonMixin, Lz4Mixin, DaoDB):\n        pass\n\n    class LzmaDaoDB(JsonMixin, LzmaMixin, DaoDB):\n        pass\n\n    class BrotliDaoDB(JsonMixin, BrotliMixin, DaoDB):\n        pass\n\n    class SnappyDaoDB(JsonMixin, SnappyMixin, DaoDB):\n        pass\n\n------------------\nDatabase structure\n------------------\n\n* data file\n* index file\n\nIndex file contains positions of records except the first one which is always zero,\nand the position for new record.\nThus, the number of items in the index file equals to the number of records.\n\nRecord id is implicit, it's the index of the record.\nThus, to get a record by id, read offsets from the index file and then read the record from data file.\n\n---------\nAlgorithm\n---------\n\nWrite:\n\n* lock index file exclusively\n* get position for the new record from the index file\n* append new record to the data file\n* write new size of data file to the index file\n* release file lock\n\nRead item by id:\n\n* Given that id is the index of record, seek to id * 16 in the index file.\n* Read the position of the record and the position of the next record from the index file, 16 bytes total.\n* Read the record from the data file, the size of record is calculated as a difference between positions.\n\nNo lock is necessary for read operation.\nThat's because append is atomic and the data written to the index file (16 bytes)\nwill never be split across pages to make this bug take into effect: https://bugzilla.kernel.org/show_bug.cgi?id=55651\n\n\n",
    "bugtrack_url": null,
    "license": "",
    "summary": "Declassed Append-Only Database",
    "version": "0.0.6",
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "edaea1e75f2478494edc50a87cdf04e67a5ba3852137d0aa0ede30d459119888",
                "md5": "a1da2648acb1e34976ba64a740fa23ed",
                "sha256": "31b1628ab1f9ee740ecb0cabe43aa77777d01509bd000857cffd2e03599763da"
            },
            "downloads": -1,
            "filename": "daodb-0.0.6-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "a1da2648acb1e34976ba64a740fa23ed",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.6",
            "size": 8563,
            "upload_time": "2023-03-18T19:32:50",
            "upload_time_iso_8601": "2023-03-18T19:32:50.098062Z",
            "url": "https://files.pythonhosted.org/packages/ed/ae/a1e75f2478494edc50a87cdf04e67a5ba3852137d0aa0ede30d459119888/daodb-0.0.6-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "59057b6e151341d9c5c36a58390a09ad962820dacfc2c8aa95e2b32c53c4a404",
                "md5": "56be17cb9a166bb73021ca5a6a6ce1af",
                "sha256": "82d497379806650b25274a8c3f0d0b7d651383ce9108a295f6c311794fc4ae20"
            },
            "downloads": -1,
            "filename": "daodb-0.0.6.tar.gz",
            "has_sig": false,
            "md5_digest": "56be17cb9a166bb73021ca5a6a6ce1af",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.6",
            "size": 7516,
            "upload_time": "2023-03-18T19:32:52",
            "upload_time_iso_8601": "2023-03-18T19:32:52.100047Z",
            "url": "https://files.pythonhosted.org/packages/59/05/7b6e151341d9c5c36a58390a09ad962820dacfc2c8aa95e2b32c53c4a404/daodb-0.0.6.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-03-18 19:32:52",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "lcname": "daodb"
}
        
AXY
Elapsed time: 0.04598s