Skip to main content

Mappings based transparently on multiple BTrees; good for rotating caches and logs.

Project description

BForests are dictionary-like objects that use multiple BTrees for a backend and support rotation of the composite trees. This supports various implementations of timed member expirations, enabling caches and semi-persistent storage. A useful and simple subclass would be to promote a key-value pair to the first (newest) bucket whenever the key is accessed, for instance. It also is useful with disabling the rotation capability.

Like btrees, bforests come in four flavors: Integer-Integer (IIBForest), Integer-Object (IOBForest), Object-Integer (OIBForest), and Object-Object (OOBForest). The examples here will deal with them in the abstract: we will create classes from the imaginary and representative BForest class, and generate keys from KeyGenerator and values from ValueGenerator. From the examples you should be able to extrapolate usage of all four types.

First let’s instantiate a bforest and look at an empty example. By default, a new bforest creates two composite btree buckets.

>>> d = BForest()
>>> list(d.keys())
[]
>>> list(d.values())
[]
>>> len(d.buckets)
2
>>> dummy_key = KeyGenerator()
>>> d.get(dummy_key)
>>> d.get(dummy_key, 42)
42

Now we’ll populate it. We’ll first create a dictionary we’ll use to compare.

>>> original = {}
>>> for i in range(10):
...     original[KeyGenerator()] = ValueGenerator()
...
>>> d.update(original)
>>> d == original
True
>>> d_keys = list(d.keys())
>>> d_keys.sort()
>>> o_keys = original.keys()
>>> o_keys.sort()
>>> d_keys == o_keys
True
>>> d_values = list(d.values())
>>> d_values.sort()
>>> o_values = original.values()
>>> o_values.sort()
>>> o_values == d_values
True
>>> d_items = list(d.items())
>>> d_items.sort()
>>> o_items = original.items()
>>> o_items.sort()
>>> o_items == d_items
True
>>> key, value = d.popitem()
>>> value == original.pop(key)
True
>>> key, value = original.popitem()
>>> value == d.pop(key)
True
>>> len(d) == len(original)
True

Now let’s rotate the buckets.

>>> d.rotateBucket()

…and we’ll do the exact same test as above, first.

>>> d == original
True
>>> d_keys = list(d.keys())
>>> d_keys.sort()
>>> o_keys = original.keys()
>>> o_keys.sort()
>>> d_keys == o_keys
True
>>> d_values = list(d.values())
>>> d_values.sort()
>>> o_values = original.values()
>>> o_values.sort()
>>> o_values == d_values
True
>>> d_items = list(d.items())
>>> d_items.sort()
>>> o_items = original.items()
>>> o_items.sort()
>>> o_items == d_items
True
>>> key, value = d.popitem()
>>> value == original.pop(key)
True
>>> key, value = original.popitem()
>>> value == d.pop(key)
True
>>> len(d) == len(original)
True

Now we’ll make a new dictionary to represent changes made after the bucket rotation.

>>> second = {}
>>> for i in range(10):
...     key = KeyGenerator()
...     value = ValueGenerator()
...     second[key] = value
...     d[key] = value
...
>>> original.update(second)

…and we’ll do almost the exact same test as above, first.

>>> d == original
True
>>> d_keys = list(d.keys())
>>> d_keys.sort()
>>> o_keys = original.keys()
>>> o_keys.sort()
>>> d_keys == o_keys
True
>>> d_values = list(d.values())
>>> d_values.sort()
>>> o_values = original.values()
>>> o_values.sort()
>>> o_values == d_values
True
>>> d_items = list(d.items())
>>> d_items.sort()
>>> o_items = original.items()
>>> o_items.sort()
>>> o_items == d_items
True
>>> key, value = d.popitem()
>>> ignore = second.pop(key, None) # keep second up-to-date
>>> value == original.pop(key)
True
>>> key, value = original.popitem()
>>> ignore = second.pop(key, None) # keep second up-to-date
>>> value == d.pop(key)
True
>>> len(d) == len(original)
True

Now if we rotate the buckets, the first set of items will be gone, but the second will remain.

>>> d.rotateBucket()
>>> d == original
False
>>> d == second
True

Let’s set a value, check the copy behavior, and then rotate it one more time.

>>> third = {KeyGenerator(): ValueGenerator()}
>>> d.update(third)
>>> copy = d.copy()
>>> copy == d
True
>>> copy != second # because second doesn't have the values of third
True
>>> list(copy.buckets[0].items()) == list(d.buckets[0].items())
True
>>> list(copy.buckets[1].items()) == list(d.buckets[1].items())
True
>>> copy[KeyGenerator()] = ValueGenerator()
>>> copy == d
False
>>> d.rotateBucket()
>>> d == third
True
>>> d.clear()
>>> d == BForest() == {}
True
>>> d.update(second)

We’ll make a value in one bucket that we’ll override in another.

>>> d[third.keys()[0]] = ValueGenerator()
>>> d.rotateBucket()
>>> d.update(third)
>>> second.update(third)
>>> d == second
True
>>> second == d
True

The tree method converts the bforest to a btree as efficiently as I know how for a common case of more items in buckets than buckets.

>>> tree = d.tree()
>>> d_items = list(d.items())
>>> d_items.sort()
>>> t_items = list(tree.items())
>>> t_items.sort()
>>> t_items == d_items
True

Finally, comparisons work similarly to dicts but in a simpleminded way–improvements welcome! We’ve already looked at a lot of examples above, but here are some additional cases

>>> d == None
False
>>> d == [1, 2]
False
>>> d != None
True
>>> None == d
False
>>> d != None
True
>>> d >= second
True
>>> d >= dict(second)
True
>>> d <= second
True
>>> d <= dict(second)
True
>>> d > second
False
>>> d > dict(second)
False
>>> d < second
False
>>> d > dict(second)
False
>>> second.popitem()[0] in d
True
>>> d > second
True
>>> d < second
False
>>> d >= second
True
>>> d <= second
False
>>> second < d
True
>>> second > d
False
>>> second <= d
True
>>> second >= d
False

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

zope.bforest-1.0.tar.gz (7.2 kB view details)

Uploaded Source

Built Distribution

zope.bforest-1.0-py2.4.egg (13.3 kB view details)

Uploaded Source

File details

Details for the file zope.bforest-1.0.tar.gz.

File metadata

  • Download URL: zope.bforest-1.0.tar.gz
  • Upload date:
  • Size: 7.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No

File hashes

Hashes for zope.bforest-1.0.tar.gz
Algorithm Hash digest
SHA256 8f02c5111410d78420501fdc8426a6d0c69429bae13aec564cf3dacb9529ccb9
MD5 fc4c56a9adca2e6e24e2391f1db6c76f
BLAKE2b-256 ec26c0559c1744cafb1326be26e08b1abf8e61bee50a6fe5571a10ed6d65bc59

See more details on using hashes here.

File details

Details for the file zope.bforest-1.0-py2.4.egg.

File metadata

File hashes

Hashes for zope.bforest-1.0-py2.4.egg
Algorithm Hash digest
SHA256 15fddbaa3759a0049555d7e94536ec58af64e40d56253bd8ff4d8452e10bce48
MD5 1b64d1d8770e206f9338bf4b17729ca7
BLAKE2b-256 690110ed520c197322741e17d9dc4c14eb2554fba74f1e4f0f04f1b1e49ea75e

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page