Skip to main content

*****************

Project description

Generational Sets

Generational sets (GSets) are designed to facilitate data synchronization between a server and clients.

Goals:

  • Make synchronization simple by sending all updates for a tree of sets at once.

  • Allow clients to be updated very quickly.

  • Reduce data-transfer volume by sending only changes.

  • Avoid conflict resolution.

Assumptions:

  • Disconnected data updates aren’t needed.

  • Clients mirror server data.

    This implies that the server data, or more specifically, the user’s view of the server data, aren’t too large to store on the client.

GSets track state by generation. A client presents a generation and is sent updates made since the presented generation. GSets can be grouped into trees with a shared generation. A client can present a single generation and be sent updates for all of the sets making up a database.

This implementation of generational sets uses ZODB to store data on the server.

High-level usage pattern

  • Define a tree of sets representing the data in an application. This may be user specific.

  • Clients make updates via REST calls to a server. They don’t make local changes except in response to server updates.

  • Client requests include their data generation.

  • Most (JSON) responses to server calls have optional updates property that contains generational updates since the generation provided by the client. When the client gets updates, which include the new generation, it applies the updates to it’s internal data store.

  • For native apps, the server sends push notifications when there are updates for a user and, in response, the client polls for the updates. This allows updates to be extremely timely without constant polling.

Note that this package only provides the data structure implementation. Wrapping the data structure in a REST interface or sending notifications is up to applications.

API

Every object in a GSet must have an id. By default, this is provided by an id attribute, but you can configure a GSet to use another attribute or some other mechanism to get an id for an object.

When an object is added to a GSet, call the add method on the Gset with the object:

>>> from zc.generationalset import GSet
>>> things = GSet()
>>> athing = Thing(42)
>>> things.add(athing)

When an object is changed, call the changed method on the Gset with the object. If object is not present in the Gset, update will raise a KeyError:

>>> things.changed(athing)
>>> things.changed(Thing(43))
Traceback (most recent call last):
...
KeyError: 43

>>> things.generational_updates(0)
{'generation': 3, 'adds': [Thing(42)]}

To remove an object, call the remove method with the object:

>>> things.remove(athing)

To get updates to a set since a given generation, call generational_updates, passing a generation:

>>> things.generational_updates(0)
{'generation': 4, 'removals': [42]}

>>> things.add(Thing(1))
>>> things.generational_updates(0)
{'generation': 5, 'removals': [42], 'adds': [Thing(1)]}
>>> things.generational_updates(3)
{'generation': 5, 'adds': [Thing(1)]}

Note that generations start at 1.

The result of calling generational_updates is a dictionary with keys:

generation

The current generation of the set

adds

Objects added since the given generation.

removals

Ids of objects removed since the given generation.

contents

All of the object in the set.

contents are returned when there have been many removals since the given generation. A generational set only keeps track of a limited number (99 by default, but configurable) of removals. If a client is too out of date for the set to have relevant removals, it returns the entire contents, instead of returning adds and removals.

GSets support iteration, and querying length and containment. They don’t currently support set operations, like intersection and union. You can also retrieve an item from a GSet using its id:

>>> len(things)
1
>>> list(things)
[Thing(1)]
>>> Thing(1) in things
True
>>> things[1]
Thing(1)

Nested sets

To define nested sets:

  • Define a parent set:

    >>> parent = GSet(superset=True)

    Note the use of the superset parameter.

  • Define child sets, and add them to the parent:

    >>> messages = GSet("messages", parent)
    >>> parent.add(messages)
    

    When defining child sets, specify an id and the parent.

We haven’t tested more than one level of nesting.

When asking for generational updates on parent sets, the adds and contents contain the generational updates for subsets, with ids, but without subset generations:

>>> messages.add(Thing(42))
>>> parent.generational_updates(0)
{'generation': 3, 'adds': [{'id': 'messages', 'adds': [Thing(42)]}]}

Changes

0.4.0 (2017-06-20)

  • Python 3 support

  • When asking for updates from generation 0, only adds are sent. Never removals, making this common case more efficient.

0.3.0 (2014-08-28)

  • Added a changed method to make intent clear when simply recording changes.

  • Fixed: exceptions were raised when objects added to generational sets quacked a little like generational sets.

0.2.0 (2014-08-10)

  • Improved subset APIs:

    • No longer need to specify superset flag.

    • Can have set and non-set children.

    • A subset can be created without a parent and the parent will be set when it’s added to a containing set.

0.1.2 (2014-06-09)

Fixed: Internal data structures were misshandled when there were more

than the maximum number of removals.

(Release 0.1.1 was made in error.)

0.1.0 (2014-06-08)

Initial release

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

zc.generationalset-0.4.0.tar.gz (13.1 kB view hashes)

Uploaded Source

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