{ "info": { "author": "Nicolas Le Manchet", "author_email": "nicolas@lemanchet.fr", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3 :: Only", "Topic :: Database", "Topic :: Software Development :: Libraries" ], "description": "Bplustree\n=========\n\n.. image:: https://travis-ci.org/NicolasLM/bplustree.svg?branch=master\n :target: https://travis-ci.org/NicolasLM/bplustree\n.. image:: https://coveralls.io/repos/github/NicolasLM/bplustree/badge.svg?branch=master\n :target: https://coveralls.io/github/NicolasLM/bplustree?branch=master\n\nAn on-disk B+tree for Python 3.\n\nIt feels like a dict, but stored on disk. When to use it?\n\n- When the data to store does not fit in memory\n- When the data needs to be persisted\n- When keeping the keys in order is important\n\nThis project is under development: the format of the file may change between\nversions. Do not use as your primary source of data.\n\nQuickstart\n----------\n\nInstall Bplustree with pip::\n\n pip install bplustree\n\nCreate a B+tree index stored on a file and use it with:\n\n.. code:: python\n\n >>> from bplustree import BPlusTree\n >>> tree = BPlusTree('/tmp/bplustree.db', order=50)\n >>> tree[1] = b'foo'\n >>> tree[2] = b'bar'\n >>> tree[1]\n b'foo'\n >>> tree.get(3)\n >>> tree.close()\n\nKeys and values\n---------------\n\nKeys must have a natural order and must be serializable to bytes. Some default\nserializers for the most common types are provided. For example to index UUIDs:\n\n.. code:: python\n\n >>> import uuid\n >>> from bplustree import BPlusTree, UUIDSerializer\n >>> tree = BPlusTree('/tmp/bplustree.db', serializer=UUIDSerializer(), key_size=16)\n >>> tree.insert(uuid.uuid1(), b'foo')\n >>> list(tree.keys())\n [UUID('48f2553c-de23-4d20-95bf-6972a89f3bc0')]\n\nValues on the other hand are always bytes. They can be of arbitrary length,\nthe parameter ``value_size=128`` defines the upper bound of value sizes that\ncan be stored in the tree itself. Values exceeding this limit are stored in\noverflow pages. Each overflowing value occupies at least a full page.\n\nIterating\n---------\n\nSince keys are kept in order, it is very efficient to retrieve elements in\norder:\n\n.. code:: python\n\n >>> for i in tree:\n ... print(i)\n ...\n 1\n 2\n >>> for key, value in tree.items():\n ... print(key, value)\n ...\n 1 b'foo'\n 2 b'bar'\n\nIt is also possible to iterate over a subset of the tree by giving a Python\nslice:\n\n.. code:: python\n\n >>> for key, value in tree.items(slice(start=0, stop=10):\n ... print(key, value)\n ...\n 1 b'foo'\n 2 b'bar'\n\nBoth methods use a generator so they don't require loading the whole content\nin memory, but copying a slice of the tree into a dict is also possible:\n\n.. code:: python\n\n >>> tree[0:10]\n {1: b'foo', 2: b'bar'}\n\n\nConcurrency\n-----------\n\nThe tree is thread-safe, it follows the multiple readers/single writer pattern.\n\nIt is safe to:\n\n- Share an instance of a ``BPlusTree`` between multiple threads\n\nIt is NOT safe to:\n\n- Share an instance of a ``BPlusTree`` between multiple processes\n- Create multiple instances of ``BPlusTree`` pointing to the same file\n\nDurability\n----------\n\nA write-ahead log (WAL) is used to ensure that the data is safe. All changes\nmade to the tree are appended to the WAL and only merged into the tree in an\noperation called a checkpoint, usually when the tree is closed. This approach\nis heavily inspired by other databases like SQLite.\n\nIf tree doesn't get closed properly (power outage, process killed...) the WAL\nfile is merged the next time the tree is opened.\n\nPerformances\n------------\n\nLike any database, there are many knobs to finely tune the engine and get the\nbest performance out of it:\n\n- ``order``, or branching factor, defines how many entries each node will hold\n- ``page_size`` is the amount of bytes allocated to a node and the length of\n read and write operations. It is best to keep it close to the block size of\n the disk\n- ``cache_size`` to keep frequently used nodes at hand. Big caches prevent the\n expensive operation of creating Python objects from raw pages but use more\n memory\n\nSome advices to efficiently use the tree:\n\n- Insert elements in ascending order if possible, prefer UUID v1 to UUID v4\n- Insert in batch with ``tree.batch_insert(iterator)`` instead of using\n ``tree.insert()`` in a loop\n- Let the tree iterate for you instead of using ``tree.get()`` in a loop\n- Use ``tree.checkpoint()`` from time to time if you insert a lot, this will\n prevent the WAL from growing unbounded\n- Use small keys and values, set their limit and overflow values accordingly\n- Store the file and WAL on a fast disk\n\nLicense\n-------\n\nMIT\nCopyright (c) 2017 Nicolas Le Manchet\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n", "description_content_type": null, "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/NicolasLM/bplustree", "keywords": "bplustree B+tree Btree database index", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "bplustree", "package_url": "https://pypi.org/project/bplustree/", "platform": "", "project_url": "https://pypi.org/project/bplustree/", "project_urls": { "Homepage": "https://github.com/NicolasLM/bplustree" }, "release_url": "https://pypi.org/project/bplustree/0.0.3/", "requires_dist": [ "rwlock", "cachetools", "temporenc; extra == 'datetime'", "pytest; extra == 'tests'", "pytest-cov; extra == 'tests'", "python-coveralls; extra == 'tests'", "pycodestyle; extra == 'tests'" ], "requires_python": "", "summary": "On-disk B+tree for Python 3", "version": "0.0.3" }, "last_serial": 3515411, "releases": { "0.0.1": [ { "comment_text": "", "digests": { "md5": "a06661660161c4f19afe78945f808fd6", "sha256": "745d956ace4ab848f93fb70bf66124e27a982bd31c0d4c43cddd1efd8238106f" }, "downloads": -1, "filename": "bplustree-0.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "a06661660161c4f19afe78945f808fd6", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 12363, "upload_time": "2017-12-11T20:22:21", "url": "https://files.pythonhosted.org/packages/d4/be/a17f90af3caae404d601c23a7e0040852dad7cca4448cc623ab76894b67a/bplustree-0.0.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "ecbed51cb2b4f62d2d43e4eb432ffdc2", "sha256": "0bfe8adc1b9b284ef7de88cdf660ac0d95576abd613400c84c3cadfcddacd637" }, "downloads": -1, "filename": "bplustree-0.0.1.tar.gz", "has_sig": false, "md5_digest": "ecbed51cb2b4f62d2d43e4eb432ffdc2", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10006, "upload_time": "2017-12-11T20:22:23", "url": "https://files.pythonhosted.org/packages/b3/22/37cf0f3823be38066b95022542ac41d0728e6f1d4f9ba74ee50c95cd2220/bplustree-0.0.1.tar.gz" } ], "0.0.2": [ { "comment_text": "", "digests": { "md5": "92086a8f7f12db0fd85a5079d3c6b467", "sha256": "4ce5a5c6b74183b76b8d5499a9311c0ed7c1a848a699c8f2ae2fd8a35b0ff1a0" }, "downloads": -1, "filename": "bplustree-0.0.2-py3-none-any.whl", "has_sig": false, "md5_digest": "92086a8f7f12db0fd85a5079d3c6b467", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 18594, "upload_time": "2018-01-03T17:28:52", "url": "https://files.pythonhosted.org/packages/66/ea/87a12d703ca9208f79a470041628ec8978e27cd9fc8ff7836b0395b856d7/bplustree-0.0.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "39f2b346ca10754f91e908977a839dd7", "sha256": "93bfd8455ff4d507cb72b6d353600a16de662ba1de2dcf443750a30425569d98" }, "downloads": -1, "filename": "bplustree-0.0.2.tar.gz", "has_sig": false, "md5_digest": "39f2b346ca10754f91e908977a839dd7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 15784, "upload_time": "2018-01-03T17:28:56", "url": "https://files.pythonhosted.org/packages/b4/88/0b54e7f14e61eb240221711b47e92ae12c1af561c5a98fd1e27c599ef8bc/bplustree-0.0.2.tar.gz" } ], "0.0.3": [ { "comment_text": "", "digests": { "md5": "e310790fe4fe5dd3f71269d1ae4e2e26", "sha256": "0d792438c1f2435b770e27f9c5be5153f6c5481a5285e6fda56487bd954f6471" }, "downloads": -1, "filename": "bplustree-0.0.3-py3-none-any.whl", "has_sig": false, "md5_digest": "e310790fe4fe5dd3f71269d1ae4e2e26", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 20908, "upload_time": "2018-01-23T21:36:44", "url": "https://files.pythonhosted.org/packages/69/9b/269c9d228307d853075e377360dd268b78e4af04b7e4715c436bcc0adcff/bplustree-0.0.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "3303c5be29213314c096236e786d6d33", "sha256": "53a2c820e7f1a444ac65d31834251dad2219d6aec6bc0853a32eb0fe40ea924d" }, "downloads": -1, "filename": "bplustree-0.0.3.tar.gz", "has_sig": false, "md5_digest": "3303c5be29213314c096236e786d6d33", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17994, "upload_time": "2018-01-23T21:36:49", "url": "https://files.pythonhosted.org/packages/45/80/c029b41c992b6a9ee7a38be686c395df8f6a5edd3f8fb1ad3a1684b12d02/bplustree-0.0.3.tar.gz" } ], "0.0.3.dev1": [ { "comment_text": "", "digests": { "md5": "be2a9d0f3499b2e60c9339be74d3f1f9", "sha256": "80b05f93e795a34eacdbf699adc2ddab2ab407eee10fe00d64a4221edd4da897" }, "downloads": -1, "filename": "bplustree-0.0.3.dev1.tar.gz", "has_sig": false, "md5_digest": "be2a9d0f3499b2e60c9339be74d3f1f9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 18001, "upload_time": "2018-01-23T21:36:47", "url": "https://files.pythonhosted.org/packages/d8/e7/305a1112ed26b2a80dc6e109f4f146ed0f3bece94fd31b3233d5d8711467/bplustree-0.0.3.dev1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "e310790fe4fe5dd3f71269d1ae4e2e26", "sha256": "0d792438c1f2435b770e27f9c5be5153f6c5481a5285e6fda56487bd954f6471" }, "downloads": -1, "filename": "bplustree-0.0.3-py3-none-any.whl", "has_sig": false, "md5_digest": "e310790fe4fe5dd3f71269d1ae4e2e26", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 20908, "upload_time": "2018-01-23T21:36:44", "url": "https://files.pythonhosted.org/packages/69/9b/269c9d228307d853075e377360dd268b78e4af04b7e4715c436bcc0adcff/bplustree-0.0.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "3303c5be29213314c096236e786d6d33", "sha256": "53a2c820e7f1a444ac65d31834251dad2219d6aec6bc0853a32eb0fe40ea924d" }, "downloads": -1, "filename": "bplustree-0.0.3.tar.gz", "has_sig": false, "md5_digest": "3303c5be29213314c096236e786d6d33", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17994, "upload_time": "2018-01-23T21:36:49", "url": "https://files.pythonhosted.org/packages/45/80/c029b41c992b6a9ee7a38be686c395df8f6a5edd3f8fb1ad3a1684b12d02/bplustree-0.0.3.tar.gz" } ] }