calendaring_sync.store.base module#
The store interface, and the storage interface a store keeps its data in.
A store only keeps data. Every sync rule lives in
Replica, and every rule about how a store
behaves, such as its transactions, its checks and its errors, lives in
StateStore. Where the data goes is a Storage, which
implements the same small set of typed operations and nothing more.
- class calendaring_sync.store.base.StateStore(storage)[source]#
Bases:
objectWhere the core keeps each scope, its records, and the change feed.
It keeps them in a
Storage, and adds every rule a store follows, whichever storage it uses. Every operation runs insidetransaction(): one that only reads runs inside any transaction, and one that writes needs a transaction opened withwrite=True. A store is safe to share between threads: one write transaction runs at a time, and where the storage setsreads_beside_writes, transactions that only read run in other threads meanwhile instead of waiting for it.Besides the errors each method lists, every operation,
transaction()andclose()can raise:TypeError, for an argument of the wrong type, before anything is read or written; a record or scope to write is checked field by fieldStoreError, if the store can’t read or write its dataUnexpectedStoreError, for any other failure inside the storage, which is a bug
No exception of the storage underneath reaches the caller.
- Parameters:
storage (
Storage) – Where the store keeps its data.
- transaction(*, write=True)[source]#
Run the operations inside the block as one transaction.
Everything the block wrote is kept if it ends normally, and nothing is kept if it raises.
- Parameters:
write (
bool) –Falsefor a block that only reads. Such a block can’t write, and a store may run it beside a write in another thread or process.- Raises:
TransactionError – If a transaction is already open in this thread.
StoreBusyError – If another process kept the store busy for too long.
StoreError – If the store was closed, or can’t start or keep the transaction.
- Return type:
- get_scope(scope_id)[source]#
Return the scope with this id, or
None.Runs inside any transaction.
- Raises:
TransactionRequiredError – If no transaction is open in this thread.
- Return type:
- put_scope(scope)[source]#
Insert the scope, or replace the one with its id.
Runs inside a write transaction.
- Raises:
TransactionRequiredError – If no transaction is open in this thread.
TransactionPermissionError – If the transaction only reads.
- Return type:
- delete_scope(scope_id)[source]#
Delete the scope and every record in it.
Runs inside a write transaction.
- Raises:
TransactionRequiredError – If no transaction is open in this thread.
TransactionPermissionError – If the transaction only reads.
- Return type:
- scopes()[source]#
Return every scope, ordered by id.
Runs inside any transaction.
- Raises:
TransactionRequiredError – If no transaction is open in this thread.
- Return type:
- insert_record(record)[source]#
Insert a new record and return the local key it got.
The record’s own
local_keyis ignored. A key is never given out twice, even after the record it went to was deleted. Runs inside a write transaction.- Raises:
RecordValueError – If the record holds what its state can’t. A record holds an edit exactly when it’s pending, in flight or in conflict, the server’s copy in a conflict exactly when it’s in conflict, and no synced copy exactly when its edit is a create. An edit holds a copy of the object unless it’s a delete, a conflict’s edit and server’s copy match its kind, and only a refused create’s conflict names a holder. The record is checked first, so this is raised outside a transaction too.
TransactionRequiredError – If no transaction is open in this thread.
TransactionPermissionError – If the transaction only reads.
UnknownScopeError – If the record’s scope doesn’t exist.
DuplicateObjectError – If another record in the scope has the record’s object id.
- Return type:
- update_record(record)[source]#
Replace the record with the same local key.
Runs inside a write transaction.
- Raises:
RecordValueError – If the record holds what its state can’t, as for
insert_record().TransactionRequiredError – If no transaction is open in this thread.
TransactionPermissionError – If the transaction only reads.
UnknownRecordError – If no record has the record’s local key.
DuplicateObjectError – If another record in the scope has the record’s object id.
- Return type:
- delete_record(local_key)[source]#
Delete the record with this local key.
Runs inside a write transaction.
- Raises:
TransactionRequiredError – If no transaction is open in this thread.
TransactionPermissionError – If the transaction only reads.
- Return type:
- get_record(local_key)[source]#
Return the record with this local key, or
None.Runs inside any transaction.
- Raises:
TransactionRequiredError – If no transaction is open in this thread.
- Return type:
- find_record(scope_id, object_id)[source]#
Return the scope’s record with this object id, or
None.Runs inside any transaction.
- Raises:
TransactionRequiredError – If no transaction is open in this thread.
- Return type:
- find_by_logical_key(scope_id, logical_key)[source]#
Return the scope’s records with this logical key, ordered by local key.
Matches as
Replica.find_by_logical_keydescribes. Runs inside any transaction.- Raises:
TransactionRequiredError – If no transaction is open in this thread.
- Return type:
- scope_records(scope_id, *, states=None)[source]#
Return the scope’s records, ordered by local key.
Runs inside any transaction.
- Parameters:
scope_id (
str) – The scope to read.states (
frozenset[RecordState] |None) – Only the records in one of these states;Nonefor every record. An empty set always returns an empty list.
- Raises:
TransactionRequiredError – If no transaction is open in this thread.
- Return type:
- removed_records(through)[source]#
Return the removed records no feed entry after
throughis about.throughis the number of a change feed entry. Each record keeps the number of the last entry about it, so these are the records removed by that entry or an earlier one, ordered by local key. Runs inside any transaction.- Raises:
TransactionRequiredError – If no transaction is open in this thread.
- Return type:
- append_entry(scope_id, kind, local_key, object_id, at)[source]#
Write the next change feed entry and return it.
Its number is one more than the last number written. Runs inside a write transaction.
- Raises:
TransactionRequiredError – If no transaction is open in this thread.
TransactionPermissionError – If the transaction only reads.
- Return type:
- entries(after, limit)[source]#
Return up to
limitkept entries numbered aboveafter, in order.Runs inside any transaction.
- Raises:
TransactionRequiredError – If no transaction is open in this thread.
- Return type:
- feed_bounds()[source]#
Return the number the feed is trimmed through, and the last number written.
Runs inside any transaction.
- Raises:
TransactionRequiredError – If no transaction is open in this thread.
- Return type:
- trim_entries(through)[source]#
Delete every entry numbered at or below
through.feed_bounds()reports the highestthroughtrimmed so far. Runs inside a write transaction.- Raises:
TransactionRequiredError – If no transaction is open in this thread.
TransactionPermissionError – If the transaction only reads.
- Return type:
- close()[source]#
Close the store. Every later transaction raises
StoreError.Transactions open in other threads end first: closing waits for them. Closing a closed store does nothing.
- Raises:
TransactionError – If this thread has a transaction open.
StoreError – If the store couldn’t release what it holds open. It counts as closed anyway.
- Return type:
- class calendaring_sync.store.base.Storage[source]#
Bases:
ABCWhere a
StateStorekeeps its data.To keep sync state somewhere new, such as in another database, implement this and a
StorageTransaction, and pass the storage toStateStore. The store adds every check, transaction rule, thread rule and error a store needs, so a storage only reads and writes.- reads_beside_writes: bool = False#
Whether a transaction that only reads can run while another thread’s write transaction is open. With
False, every transaction waits for the one before it to end. Set it toTrueonly where a read sees the data as the last commit left it until it ends, whatever a write does meanwhile; reads in other threads then run at the same time too, sobegin()and the transactions it returns must be safe for that.
- abstractmethod begin(*, write)[source]#
Start a transaction and return it.
The store runs one write transaction at a time, and transactions that only read beside it only if
reads_beside_writesis set. If this raises, it leaves nothing open.- Return type:
- close()[source]#
Release what the storage holds open.
The store calls it once, after every transaction ended.
- Return type:
- error(exc)[source]#
Return the store error for an exception the storage raised, or
None.Turn the failures of whatever the storage uses, such as a file it can’t open, into
StoreErroror one of its subclasses. The store reports any exception this returnsNonefor as a bug in the storage.- Return type:
- class calendaring_sync.store.base.StorageTransaction(*, write)[source]#
Bases:
ABCOne transaction on a
Storage, whichStorage.begin()returns.It holds whatever its transaction needs, such as a connection or a view of the data, so a storage keeps no state per thread. Its data operations are the ones
StateStoreoffers, without the checks:StateStorecalls them only inside this transaction, after it checked the arguments, the records and whether the transaction may write, and turns every exception they raise into a store error. Each returns what theStateStoremethod of the same name returns.- Parameters:
write (
bool) – Whether the transaction may write.
- write#
Whether the transaction may write.
- abstractmethod rollback()[source]#
Discard what the transaction wrote, and end it.
It’s also called after
commit()raised, so it ends whatever the transaction still holds open.- Return type:
- abstractmethod get_scope(scope_id)[source]#
Do what
StateStore.get_scope()does, without its checks.
- abstractmethod put_scope(scope)[source]#
Do what
StateStore.put_scope()does, without its checks.- Return type:
- abstractmethod delete_scope(scope_id)[source]#
Do what
StateStore.delete_scope()does, without its checks.- Return type:
- abstractmethod scopes()[source]#
Do what
StateStore.scopes()does, without its checks.
- abstractmethod insert_record(record)[source]#
Do what
StateStore.insert_record()does, without its checks.- Return type:
- abstractmethod update_record(record)[source]#
Do what
StateStore.update_record()does, without its checks.- Return type:
- abstractmethod delete_record(local_key)[source]#
Do what
StateStore.delete_record()does, without its checks.- Return type:
- abstractmethod get_record(local_key)[source]#
Do what
StateStore.get_record()does, without its checks.
- abstractmethod find_record(scope_id, object_id)[source]#
Do what
StateStore.find_record()does, without its checks.
- abstractmethod find_by_logical_key(scope_id, logical_key)[source]#
Do what
StateStore.find_by_logical_key()does, without its checks.
- abstractmethod scope_records(scope_id)[source]#
Return every record of the scope, ordered by local key.
- scope_records_in(scope_id, states)[source]#
Return the scope’s records in one of
states, ordered by local key.This filters what
scope_records()returns. A storage that can filter where it keeps its records, such as with an index, overrides it. It never gets an empty set.
- abstractmethod removed_records(through)[source]#
Do what
StateStore.removed_records()does, without its checks.
- abstractmethod append_entry(scope_id, kind, local_key, object_id, at)[source]#
Do what
StateStore.append_entry()does, without its checks.- Return type:
- abstractmethod entries(after, limit)[source]#
Do what
StateStore.entries()does, without its checks.
- abstractmethod feed_bounds()[source]#
Do what
StateStore.feed_bounds()does, without its checks.
- abstractmethod trim_entries(through)[source]#
Do what
StateStore.trim_entries()does, without its checks.- Return type: