- All Implemented Interfaces:
- com.firebase.client.core.PersistentCache
public class SqlPersistentCache
extends Object
implements com.firebase.client.core.PersistentCache
This class is an Android/SQL backed implementation of PersistenceCache.
The implementation uses 3 tables for persistence:
- writes: A list of all currently outstanding (visible) writes. A row represents a single write containing a
across restarts unique write id, the path string, the type which can be 'o' for an overwrite or 'm' for a merge,
and the serialized node wrapped. Part number is NULL for normal writes. Large writes (>256K) are split into
multiple rows with increasing part number.
- complete: A path and an optional query id to indicate the cached value at that path (and for that query)
can be considered complete. A NULL value is used for a query that loads all data. If a complete-entry dominates
others (e.g. at a deeper path), the other complete entries are deleted
- serverCache: Cached nodes from the server. A row represents a complete node at a path.
To allow for fast writes, a row added later can overwrite a part of a previous row at a higher path. When loading
the cache, all rows at a path and deeper need to be combined to get the latest cached node. To ensure this
representation is unambiguous, updates for a given path need to delete any node at the same or any deeper path.
There is a size threshold after which children-nodes are split up and each child is saved individually (and can
be split up again). This is so deeper reads don't need to read massive amounts of data and single rows don't
have excessive amount of data in them.
Example demonstrating deeper overwrites with the following rows:
/foo/: {"bar": 1, "baz": 2, "qux": 3}
/foo/bar/: 4
/foo/qux/: null
/foo/quu/: 5
=> yields {"bar": 4, "baz": 2, "quu": 5} at /foo
Large leaf nodes might be split into multiple parts to avoid the limitiation of ~1MB per row for the SQL cursor.
Consecutive leaf node parts will be saved as without a trailing slash at the end.
/leaf/node/path/.part-0000
/leaf/node/path/.part-0001
...
To ensure prefix queries work on paths, each path must start and end with a '/'.
Schema:
- writes table
+ id: unique id across restarts
+ path: path for this write as string
+ node: serialized node/merge-map as JSON (utf-8) bytes
+ part: The part number for multi-part/split writes starting with 0, NULL if not split
+ type: 'o' for overwrite and 'm' for merge
- serverCache
+ path: path for this node as string
+ value: serialized node as JSON (utf-8) bytes
- complete
+ path: path that is complete as string
+ queryId: the queryId as string or NULL if this query loads all data
This class is intended to be shared between different contexts and threads and must therefore be threadsafe.