##! The Broker-based data store API and its various options.

@load ./main
@load base/bif/data.bif

module Broker;

export {
	## The default frequency at which clones will attempt to
	## reconnect/resynchronize with their master in the event that they become
	## disconnected.
	const default_clone_resync_interval = 10sec &redef;

	## The duration after which a clone that is disconnected from its master
	## will begin to treat its local cache as stale.  In the stale state,
	## queries to the cache will timeout.  A negative value indicates that
	## the local cache is never treated as stale.
	const default_clone_stale_interval = 5min &redef;

	## The maximum amount of time that a disconnected clone will
	## buffer data store mutation commands.  If the clone reconnects before
	## this time, it will replay all stored commands.  Note that this doesn't
	## completely prevent the loss of store updates: all mutation messages
	## are fire-and-forget and not explicitly acknowledged by the master.
	## A negative/zero value indicates to never buffer commands.
	const default_clone_mutation_buffer_interval = 2min &redef;

	## If set to true, the current node is the master node for Broker stores
	## backing Zeek tables. By default this value will be automatically set to
	## true in standalone mode, and on the manager node of a cluster. This value
	## should not typically be changed manually.
	const table_store_master = T &redef;

	## The directory used for storing persistent database files when using Broker
        ## store backed Zeek tables.
	const table_store_db_directory = "." &redef;

	## Whether a data store query could be completed or not.
	type QueryStatus: enum {
		SUCCESS,
		FAILURE,
	};

	## The result of a data store query.
	type QueryResult: record {
		## Whether the query completed or not.
		status: Broker::QueryStatus;
		## The result of the query.  Certain queries may use a particular
		## data type (e.g. querying store size always returns a count, but
		## a lookup may return various data types).
		result: Broker::Data;
	};

	## Enumerates the possible storage backends.
	type BackendType: enum {
		MEMORY,
		SQLITE,
	};

	## Behavior when the SQLite database file is found to be corrupt
	## or otherwise fails to open or initialize.
	type SQLiteFailureMode: enum {
		SQLITE_FAILURE_MODE_FAIL,   ##< Fail during initialization.
		SQLITE_FAILURE_MODE_DELETE, ##< Attempt to delete the database file and retry.
	};

	## Values supported for SQLite's PRAGMA synchronous statement.
	type SQLiteSynchronous: enum {
		SQLITE_SYNCHRONOUS_OFF,
		SQLITE_SYNCHRONOUS_NORMAL,
		SQLITE_SYNCHRONOUS_FULL,
		SQLITE_SYNCHRONOUS_EXTRA,
	};

	## Values supported for SQLite's PRAGMA journal_mode statement.
	type SQLiteJournalMode: enum {
		SQLITE_JOURNAL_MODE_DELETE,
		SQLITE_JOURNAL_MODE_WAL,
	};

	## Options to tune the SQLite storage backend.
	type SQLiteOptions: record {
		## File system path of the database.
		## If left empty, will be derived from the name of the store,
		## and use the '.sqlite' file suffix.
		path: string &default = "";

		## If set, runs the PRAGMA synchronous statement with the
		## provided value after connecting to the SQLite database. See
		## `SQLite's synchronous documentation <https://www.sqlite.org/pragma.html#pragma_synchronous>`_
		## for more details around performance and data safety trade offs.
		synchronous: SQLiteSynchronous &optional;

		## If set, runs the PRAGMA journal_mode statement with the
		## provided value after connecting to the SQLite database. See
		## `SQLite's journal_mode documentation <https://www.sqlite.org/pragma.html#pragma_journal_mode>`_
		## for more details around performance, data safety trade offs
		## and interaction with the PRAGMA synchronous statement.
		journal_mode: SQLiteJournalMode &optional;

		## What to do when the database is found corrupt during
		## initialization. When set to SQLITE_FAILURE_MODE_DELETE,
		## the old file is deleted to allow creation of a new and empty
		## database. By default, an error is reported, the corrupt
		## database file left in place and the data store is in a
		## non-functional state.
		failure_mode: SQLiteFailureMode &default=SQLITE_FAILURE_MODE_FAIL;

		## When true, run the PRAGMA integrity_check statement after
		## opening the database and fail according to ``failure_mode``.
		## PRAGMA integrity_check may take a non-negligible amount of time,
		## so you are advised to experiment with the expected sizes
		## of your databases if that is acceptable. Corrupted databases
		## should be reliably detected when this setting is ``T``.
		integrity_check: bool &default=F;
	};

	## Options to tune the particular storage backends.
	type BackendOptions: record {
		sqlite: SQLiteOptions &default = SQLiteOptions();
	};

	## Create a master data store which contains key-value pairs.
	##
	## name: a unique name for the data store.
	##
	## b: the storage backend to use.
	##
	## options: tunes how some storage backends operate.
	##
	## Returns: a handle to the data store for which a subsequent call to
	##          :zeek:see:`Broker::is_closed` will return true if the store
	##          could not be created/opened.
	global create_master: function(name: string, b: BackendType &default = MEMORY,
	                               options: BackendOptions &default = BackendOptions()): opaque of Broker::Store
	                               &deprecated="Remove in v9.1. Broker stores have been deprecated. To distribute state across cluster nodes, use the new &publish_on_change attribute for global sets/tables, or leverage explicit remote events with Cluster::publish(). For state persistence, use the storage framework.";

	## Create a clone of a master data store which may live with a remote peer.
	## A clone automatically synchronizes to the master by
	## receiving modifications and applying them locally.  Direct modifications
	## are not possible, they must be sent through the master store, which then
	## automatically broadcasts the changes out to clones.  But queries may be
	## made directly against the local cloned copy, which may be resolved
	## quicker than reaching out to a remote master store.
	##
	## name: the unique name which identifies the master data store.
	##
	## resync_interval: the frequency at which a clone that is disconnected from
	##                  its master attempts to reconnect with it.
	##
	## stale_interval: the duration after which a clone that is disconnected
	##                 from its master will begin to treat its local cache as
	##                 stale.  In this state, queries to the clone will timeout.
	##                 A negative value indicates that the local cache is never
	##                 treated as stale.
	##
	## mutation_buffer_interval: the amount of time to buffer data store update
	##                           messages once a clone detects its master is
	##                           unavailable.  If the clone reconnects before
	##                           this time, it will replay all buffered
	##                           commands.  Note that this doesn't completely
	##                           prevent the loss of store updates: all mutation
	##                           messages are fire-and-forget and not explicitly
	##                           acknowledged by the master.  A negative/zero
	##                           value indicates that commands never buffer.
	##
	## Returns: a handle to the data store for which a subsequent call to
	##          :zeek:see:`Broker::is_closed` will return true if the store
	##          could not be created/opened.
	global create_clone: function(name: string,
	                              resync_interval: interval &default = default_clone_resync_interval,
	                              stale_interval: interval &default = default_clone_stale_interval,
	                              mutation_buffer_interval: interval &default = default_clone_mutation_buffer_interval): opaque of Broker::Store
	                              &deprecated="Remove in v9.1. Broker stores have been deprecated. To distribute state across cluster nodes, use the new &publish_on_change attribute for global sets/tables, or leverage explicit remote events with Cluster::publish(). For state persistence, use the storage framework.";

	## Close a data store.
	##
	## h: a data store handle.
	##
	## Returns: true if store was valid and is now closed.  The handle can no
	##          longer be used for data store operations.
	global close: function(h: opaque of Broker::Store): bool;

	## Check if a store is closed or not.
	##
	## Returns: true if the store is closed.
	global is_closed: function(h: opaque of Broker::Store): bool;

	## Get the name of a store.
	##
	## Returns: the name of the store.
	global store_name: function(h: opaque of Broker::Store): string;

	## Check if a key exists in a data store.
	##
	## h: the handle of the store to query.
	##
	## k: the key to lookup.
	##
	## Returns: True if the key exists in the data store.
	global exists: function(h: opaque of Broker::Store, k: any): QueryResult;

	## Lookup the value associated with a key in a data store.
	##
	## h: the handle of the store to query.
	##
	## k: the key to lookup.
	##
	## Returns: the result of the query.
	global get: function(h: opaque of Broker::Store, k: any): QueryResult;

	## Insert a key-value pair into the store, but only if the key does not
	## already exist.
	##
	## h: the handle of the store to modify.
	##
	## k: the key to insert.
	##
	## v: the value to insert.
	##
	## e: the expiration interval of the key-value pair.
	##
	## Returns: the result of the query which is a boolean data value that is
	##          true if the insertion happened, or false if it was rejected
	##          due to the key already existing.
	global put_unique: function(h: opaque of Broker::Store,
	                            k: any, v: any, e: interval &default=0sec): QueryResult;

	## Retrieve a specific index from an existing container value. This
	## is supported for values of types set, table, and vector.
	##
	## h: the handle of the store to query.
	##
	## k: the key of the container value to lookup.
	##
	## i: the index to retrieve from the container value.
	##
	## Returns: For tables and vectors, the value at the given index, or
	##          failure if the index doesn't exist. For sets, a boolean
	##          indicating whether the index exists. Returns failure if the key
	##          does not exist at all.
	global get_index_from_value: function(h: opaque of Broker::Store,
	                                      k: any, i: any): QueryResult;

	## Insert a key-value pair into the store.
	##
	## h: the handle of the store to modify.
	##
	## k: the key to insert.
	##
	## v: the value to insert.
	##
	## e: the expiration interval of the key-value pair.
	##
	## Returns: false if the store handle was not valid.
	global put: function(h: opaque of Broker::Store,
	                     k: any, v: any, e: interval &default=0sec) : bool;

	## Remove a key-value pair from the store.
	##
	## h: the handle of the store to modify.
	##
	## k: the key to remove.
	##
	## Returns: false if the store handle was not valid.
	global erase: function(h: opaque of Broker::Store, k: any) : bool;

	## Increments an existing value by a given amount. This is supported for all
	## numerical types, as well as for timestamps.
	##
	## h: the handle of the store to modify.
	##
	## k: the key whose associated value is to be modified. The key must
	##    already exist.
	##
	## a: the amount to increment the value by.
	##
	## e: the new expiration interval of the modified key. If null, the
	##    current expiration time isn't changed.
	##
	## Returns: false if the store handle was not valid.
	global increment: function(h: opaque of Broker::Store, k: any,
	                           a: any &default = 1,
	                           e: interval &default=0sec) : bool;

	## Decrements an existing value by a given amount. This is supported for all
	## numerical types, as well as for timestamps.
	##
	## h: the handle of the store to modify.
	##
	## k: the key whose associated value is to be modified. The key must
	##    already exist.
	##
	## amount: the amount to decrement the value by.
	##
	## e: the new expiration interval of the modified key. If null, the current
	##    expiration time isn't changed.
	##
	## Returns: false if the store handle was not valid.
	global decrement: function(h: opaque of Broker::Store, k: any,
	                           a: any &default = 1,
	                           e: interval &default=0sec) : bool;

	## Extends an existing string with another.
	##
	## h: the handle of the store to modify.
	##
	## k: the key whose associated value is to be modified. The key must
	##    already exist.
	##
	## s: the string to append.
	##
	## e: the new expiration interval of the modified key. If null, the
	##    current expiration time isn't changed.
	##
	## Returns: false if the store handle was not valid.
	global append: function(h: opaque of Broker::Store, k: any, s: string,
	                        e: interval &default=0sec) : bool;

	## Inserts an element into an existing set.
	##
	## h: the handle of the store to modify.
	##
	## k: the key whose associated value is to be modified. The key must
	##    already exist.
	##
	## i: the index to insert into the set.
	##
	## e: the new expiration interval of the modified key. If null, the
	##    current expiration time isn't changed.
	##
	## Returns: false if the store handle was not valid.
	global insert_into_set: function(h: opaque of Broker::Store,
	                                 k: any, i: any,
	                                 e: interval &default=0sec) : bool;

	## Inserts an element into an existing table.
	##
	## h: the handle of the store to modify.
	##
	## k: the key whose associated value is to be modified. The key must
	##    already exist.
	##
	## i: the index to insert into the table
	##
	## v: the value to associate with the index.
	##
	## e: the new expiration interval of the modified key. If null, the
	##    current expiration time isn't changed.
	##
	## Returns: false if the store handle was not valid.
	global insert_into_table: function(h: opaque of Broker::Store,
	                                   k: any, i: any, v: any,
	                                   e: interval &default=0sec) : bool;

	## Removes an element from an existing set or table.
	##
	## h: the handle of the store to modify.
	##
	## k: the key whose associated value is to be modified. The key must
	##    already exist.
	##
	## i: the index to remove from the set or table.
	##
	## e: the new expiration interval of the modified key. If null, the
	##    current expiration time isn't changed.
	##
	## Returns: false if the store handle was not valid.
	global remove_from: function(h: opaque of Broker::Store,
	                             k: any, i: any,
	                             e: interval &default=0sec) : bool;

	## Appends an element to an existing vector.
	##
	## h: the handle of the store to modify.
	##
	## k: the key whose associated value is to be modified. The key must
	##    already exist.
	##
	## b: the value to append to the vector.
	##
	## e: the new expiration interval of the modified key. If null, the
	##    current expiration time isn't changed.
	##
	## Returns: false if the store handle was not valid.
	global push: function(h: opaque of Broker::Store,
	                      k: any, v: any,
	                      e: interval &default=0sec) : bool;

	## Removes the last element of an existing vector.
	##
	## h: the handle of the store to modify.
	##
	## k: the key whose associated value is to be modified. The key must
	##    already exist.
	##
	## e: the new expiration interval of the modified key. If null, the
	##    current expiration time isn't changed.
	##
	## Returns: false if the store handle was not valid.
	global pop: function(h: opaque of Broker::Store,
	                     k: any,
	                     e: interval &default=0sec) : bool;

	## Returns a set with all of a store's keys. The results reflect a snapshot
	## in time that may diverge from reality soon afterwards.   When accessing
	## any of the element, it may no longer actually be there. The function is
	## also expensive for large stores, as it copies the complete set.
	##
	## Returns: a set with the keys.  If you expect the keys to be of
	##          non-uniform type, consider using
	##          :zeek:see:`Broker::set_iterator` to iterate over the result.
	global keys: function(h: opaque of Broker::Store): QueryResult;

	## Deletes all of a store's content, it will be empty afterwards.
	##
	## Returns: false if the store handle was not valid.
	global clear: function(h: opaque of Broker::Store) : bool;

	##########################
	# Data API               #
	##########################

	## Convert any Zeek value to communication data.
	##
	## .. note:: Normally you won't need to use this function as data
	##    conversion happens implicitly when passing Zeek values into Broker
	##    functions.
	##
	## d: any Zeek value to attempt to convert (not all types are supported).
	##
	## Returns: the converted communication data.  If the supplied Zeek data
	##          type does not support conversion to communication data, the
	##          returned record's optional field will not be set.
	global data: function(d: any): Broker::Data;

	## Retrieve the type of data associated with communication data.
	##
	## d: the communication data.
	##
	## Returns: The data type associated with the communication data.
	##          Note that Broker represents records in the same way as
	##          vectors, so there is no "record" type.
	global data_type: function(d: Broker::Data): Broker::DataType;

	## Create communication data of type "set".
	global set_create: function(): Broker::Data;

	## Remove all elements within a set.
	##
	## s: the set to clear.
	##
	## Returns: always true.
	global set_clear: function(s: Broker::Data) : bool;

	## Get the number of elements within a set.
	##
	## s: the set to query.
	##
	## Returns: the number of elements in the set.
	global set_size: function(s: Broker::Data): count;

	## Check if a set contains a particular element.
	##
	## s: the set to query.
	##
	## key: the element to check for existence.
	##
	## Returns: true if the key exists in the set.
	global set_contains: function(s: Broker::Data, key: any) : bool;

	## Insert an element into a set.
	##
	## s: the set to modify.
	##
	## key: the element to insert.
	##
	## Returns: true if the key was inserted, or false if it already existed.
	global set_insert: function(s: Broker::Data, key: any) : bool;

	## Remove an element from a set.
	##
	## s: the set to modify.
	##
	## key: the element to remove.
	##
	## Returns: true if the element existed in the set and is now removed.
	global set_remove: function(s: Broker::Data, key: any) : bool;

	## Create an iterator for a set.  Note that this makes a copy of the set
	## internally to ensure the iterator is always valid.
	##
	## s: the set to iterate over.
	##
	## Returns: an iterator.
	global set_iterator: function(s: Broker::Data): opaque of Broker::SetIterator;

	## Check if there are no more elements to iterate over.
	##
	## it: an iterator.
	##
	## Returns: true if there are no more elements to iterator over, i.e.
	##          the iterator is one-past-the-final-element.
	global set_iterator_last: function(it: opaque of Broker::SetIterator) : bool;

	## Advance an iterator.
	##
	## it: an iterator.
	##
	## Returns: true if the iterator, after advancing, still references an element
	##          in the collection.  False if the iterator, after advancing, is
	##          one-past-the-final-element.
	global set_iterator_next: function(it: opaque of Broker::SetIterator) : bool;

	## Retrieve the data at an iterator's current position.
	##
	## it: an iterator.
	##
	## Returns: element in the collection that the iterator currently references.
	global set_iterator_value: function(it: opaque of Broker::SetIterator): Broker::Data;

	## Create communication data of type "table".
	global table_create: function(): Broker::Data;

	## Remove all elements within a table.
	##
	## t: the table to clear.
	##
	## Returns: always true.
	global table_clear: function(t: Broker::Data) : bool;

	## Get the number of elements within a table.
	##
	## t: the table to query.
	##
	## Returns: the number of elements in the table.
	global table_size: function(t: Broker::Data): count;

	## Check if a table contains a particular key.
	##
	## t: the table to query.
	##
	## key: the key to check for existence.
	##
	## Returns: true if the key exists in the table.
	global table_contains: function(t: Broker::Data, key: any) : bool;

	## Insert a key-value pair into a table.
	##
	## t: the table to modify.
	##
	## key: the key at which to insert the value.
	##
	## val: the value to insert.
	##
	## Returns: true if the key-value pair was inserted, or false if the key
	##          already existed in the table.
	global table_insert: function(t: Broker::Data, key: any, val: any): Broker::Data;

	## Remove a key-value pair from a table.
	##
	## t: the table to modify.
	##
	## key: the key to remove from the table.
	##
	## Returns: the value associated with the key.  If the key did not exist, then
	##          the optional field of the returned record is not set.
	global table_remove: function(t: Broker::Data, key: any): Broker::Data;

	## Retrieve a value from a table.
	##
	## t: the table to query.
	##
	## key: the key to lookup.
	##
	## Returns: the value associated with the key.  If the key did not exist, then
	##          the optional field of the returned record is not set.
	global table_lookup: function(t: Broker::Data, key: any): Broker::Data;

	## Create an iterator for a table.  Note that this makes a copy of the table
	## internally to ensure the iterator is always valid.
	##
	## t: the table to iterate over.
	##
	## Returns: an iterator.
	global table_iterator: function(t: Broker::Data): opaque of Broker::TableIterator;

	## Check if there are no more elements to iterate over.
	##
	## it: an iterator.
	##
	## Returns: true if there are no more elements to iterator over, i.e.
	##          the iterator is one-past-the-final-element.
	global table_iterator_last: function(it: opaque of Broker::TableIterator) : bool;

	## Advance an iterator.
	##
	## it: an iterator.
	##
	## Returns: true if the iterator, after advancing, still references an element
	##          in the collection.  False if the iterator, after advancing, is
	##          one-past-the-final-element.
	global table_iterator_next: function(it: opaque of Broker::TableIterator) : bool;

	## Retrieve the data at an iterator's current position.
	##
	## it: an iterator.
	##
	## Returns: element in the collection that the iterator currently references.
	global table_iterator_value: function(it: opaque of Broker::TableIterator): Broker::TableItem;

	## Create communication data of type "vector".
	global vector_create: function(): Broker::Data;

	## Remove all elements within a vector.
	##
	## v: the vector to clear.
	##
	## Returns: always true.
	global vector_clear: function(v: Broker::Data) : bool;

	## Get the number of elements within a vector.
	##
	## v: the vector to query.
	##
	## Returns: the number of elements in the vector.
	global vector_size: function(v: Broker::Data): count;

	## Insert an element into a vector at a particular position, possibly displacing
	## existing elements (insertion always grows the size of the vector by one).
	##
	## v: the vector to modify.
	##
	## d: the element to insert.
	##
	## idx: the index at which to insert the data.  If it is greater than the
	##      current size of the vector, the element is inserted at the end.
	##
	## Returns: always true.
	global vector_insert: function(v: Broker::Data, idx: count, d: any) : bool;

	## Replace an element in a vector at a particular position.
	##
	## v: the vector to modify.
	##
	## d: the element to insert.
	##
	## idx: the index to replace.
	##
	## Returns: the value that was just evicted.  If the index was larger than any
	##          valid index, the optional field of the returned record is not set.
	global vector_replace: function(v: Broker::Data, idx: count, d: any): Broker::Data;

	## Remove an element from a vector at a particular position.
	##
	## v: the vector to modify.
	##
	## idx: the index to remove.
	##
	## Returns: the value that was just evicted.  If the index was larger than any
	##          valid index, the optional field of the returned record is not set.
	global vector_remove: function(v: Broker::Data, idx: count): Broker::Data;

	## Lookup an element in a vector at a particular position.
	##
	## v: the vector to query.
	##
	## idx: the index to lookup.
	##
	## Returns: the value at the index.  If the index was larger than any
	##          valid index, the optional field of the returned record is not set.
	global vector_lookup: function(v: Broker::Data, idx: count): Broker::Data;

	## Create an iterator for a vector.  Note that this makes a copy of the vector
	## internally to ensure the iterator is always valid.
	##
	## v: the vector to iterate over.
	##
	## Returns: an iterator.
	global vector_iterator: function(v: Broker::Data): opaque of Broker::VectorIterator;

	## Check if there are no more elements to iterate over.
	##
	## it: an iterator.
	##
	## Returns: true if there are no more elements to iterator over, i.e.
	##          the iterator is one-past-the-final-element.
	global vector_iterator_last: function(it: opaque of Broker::VectorIterator) : bool;

	## Advance an iterator.
	##
	## it: an iterator.
	##
	## Returns: true if the iterator, after advancing, still references an element
	##          in the collection.  False if the iterator, after advancing, is
	##          one-past-the-final-element.
	global vector_iterator_next: function(it: opaque of Broker::VectorIterator) : bool;

	## Retrieve the data at an iterator's current position.
	##
	## it: an iterator.
	##
	## Returns: element in the collection that the iterator currently references.
	global vector_iterator_value: function(it: opaque of Broker::VectorIterator): Broker::Data;

	## Create communication data of type "record".
	##
	## sz: the number of fields in the record.
	##
	## Returns: record data, with all fields uninitialized.
	global record_create: function(sz: count): Broker::Data;

	## Get the number of fields within a record.
	##
	## r: the record to query.
	##
	## Returns: the number of fields in the record.
	global record_size: function(r: Broker::Data): count;

	## Replace a field in a record at a particular position.
	##
	## r: the record to modify.
	##
	## d: the new field value to assign.
	##
	## idx: the index to replace.
	##
	## Returns: false if the index was larger than any valid index, else true.
	global record_assign: function(r: Broker::Data, idx: count, d: any) : bool;

	## Lookup a field in a record at a particular position.
	##
	## r: the record to query.
	##
	## idx: the index to lookup.
	##
	## Returns: the value at the index.  The optional field of the returned record
	##          may not be set if the field of the record has no value or if the
	##          index was not valid.
	global record_lookup: function(r: Broker::Data, idx: count): Broker::Data;

	## Create an iterator for a record.  Note that this makes a copy of the record
	## internally to ensure the iterator is always valid.
	##
	## r: the record to iterate over.
	##
	## Returns: an iterator.
	global record_iterator: function(r: Broker::Data): opaque of Broker::RecordIterator;

	## Check if there are no more elements to iterate over.
	##
	## it: an iterator.
	##
	## Returns: true if there are no more elements to iterator over, i.e.
	##          the iterator is one-past-the-final-element.
	global record_iterator_last: function(it: opaque of Broker::RecordIterator) : bool;

	## Advance an iterator.
	##
	## it: an iterator.
	##
	## Returns: true if the iterator, after advancing, still references an element
	##          in the collection.  False if the iterator, after advancing, is
	##          one-past-the-final-element.
	global record_iterator_next: function(it: opaque of Broker::RecordIterator) : bool;

	## Retrieve the data at an iterator's current position.
	##
	## it: an iterator.
	##
	## Returns: element in the collection that the iterator currently references.
	global record_iterator_value: function(it: opaque of Broker::RecordIterator): Broker::Data;
}

@load base/bif/store.bif

module Broker;

function create_master(name: string, b: BackendType &default = MEMORY,
                       options: BackendOptions &default = BackendOptions()): opaque of Broker::Store
	{
	if ( Cluster::backend != Cluster::CLUSTER_BACKEND_BROKER && Cluster::backend != Cluster::CLUSTER_BACKEND_NONE )
		Reporter::fatal(fmt("Call to Broker::create_master() with non-Broker backend %s selected", Cluster::backend));

@pragma push ignore-deprecations
	return __create_master(name, b, options);
@pragma pop
	}

function create_clone(name: string,
                      resync_interval: interval &default = default_clone_resync_interval,
                      stale_interval: interval &default = default_clone_stale_interval,
                      mutation_buffer_interval: interval &default = default_clone_mutation_buffer_interval): opaque of Broker::Store
	{
	if ( Cluster::backend != Cluster::CLUSTER_BACKEND_BROKER && Cluster::backend != Cluster::CLUSTER_BACKEND_NONE )
		Reporter::fatal(fmt("Call to Broker::create_clone() with non-Broker backend %s selected", Cluster::backend));

@pragma push ignore-deprecations
	return __create_clone(name, resync_interval, stale_interval,
	                      mutation_buffer_interval);
@pragma pop
	}

function close(h: opaque of Broker::Store): bool
	{
	return __close(h);
	}

function is_closed(h: opaque of Broker::Store): bool
	{
	return __is_closed(h);
	}

function store_name(h: opaque of Broker::Store): string
	{
	return __store_name(h);
	}

function exists(h: opaque of Broker::Store, k: any): QueryResult
	{
	return __exists(h, k);
	}

function get(h: opaque of Broker::Store, k: any): QueryResult
	{
	return __get(h, k);
	}

function put_unique(h: opaque of Broker::Store, k: any, v: any,
             e: interval &default=0sec): QueryResult
    {
    return __put_unique(h, k, v, e);
    }

function get_index_from_value(h: opaque of Broker::Store, k: any, i: any): QueryResult
	{
	return __get_index_from_value(h, k, i);
	}

function keys(h: opaque of Broker::Store): QueryResult
	{
	return __keys(h);
	}

function put(h: opaque of Broker::Store, k: any, v: any, e: interval) : bool
	{
	return __put(h, k, v, e);
	}

function erase(h: opaque of Broker::Store, k: any) : bool
	{
	return __erase(h, k);
	}

function increment(h: opaque of Broker::Store, k: any, a: any, e: interval) : bool
	{
	return __increment(h, k, a, e);
	}

function decrement(h: opaque of Broker::Store, k: any, a: any, e: interval) : bool
	{
	return __decrement(h, k, a, e);
	}

function append(h: opaque of Broker::Store, k: any, s: string, e: interval) : bool
	{
	return __append(h, k, s, e);
	}

function insert_into_set(h: opaque of Broker::Store, k: any, i: any, e: interval) : bool
	{
	return __insert_into_set(h, k, i, e);
	}

function insert_into_table(h: opaque of Broker::Store, k: any, i: any, v: any, e: interval) : bool
	{
	return __insert_into_table(h, k, i, v, e);
	}

function remove_from(h: opaque of Broker::Store, k: any, i: any, e: interval) : bool
	{
	return __remove_from(h, k, i, e);
	}

function push(h: opaque of Broker::Store, k: any, v: any, e: interval) : bool
	{
	return __push(h, k, v, e);
	}

function pop(h: opaque of Broker::Store, k: any, e: interval) : bool
	{
	return __pop(h, k, e);
	}

function clear(h: opaque of Broker::Store) : bool
	{
	return __clear(h);
	}

function data_type(d: Broker::Data): Broker::DataType
	{
	return __data_type(d);
	}

function data(d: any): Broker::Data
	{
	return __data(d);
	}

function set_create(): Broker::Data
	{
	return __set_create();
	}

function set_clear(s: Broker::Data) : bool
	{
	return __set_clear(s);
	}

function set_size(s: Broker::Data): count
	{
	return __set_size(s);
	}

function set_contains(s: Broker::Data, key: any) : bool
	{
	return __set_contains(s, key);
	}

function set_insert(s: Broker::Data, key: any) : bool
	{
	return __set_insert(s, key);
	}

function set_remove(s: Broker::Data, key: any) : bool
	{
	return __set_remove(s, key);
	}

function set_iterator(s: Broker::Data): opaque of Broker::SetIterator
	{
	return __set_iterator(s);
	}

function set_iterator_last(it: opaque of Broker::SetIterator) : bool
	{
	return __set_iterator_last(it);
	}

function set_iterator_next(it: opaque of Broker::SetIterator) : bool
	{
	return __set_iterator_next(it);
	}

function set_iterator_value(it: opaque of Broker::SetIterator): Broker::Data
	{
	return __set_iterator_value(it);
	}

function table_create(): Broker::Data
	{
	return __table_create();
	}

function table_clear(t: Broker::Data) : bool
	{
	return __table_clear(t);
	}

function table_size(t: Broker::Data): count
	{
	return __table_size(t);
	}

function table_contains(t: Broker::Data, key: any) : bool
	{
	return __table_contains(t, key);
	}

function table_insert(t: Broker::Data, key: any, val: any): Broker::Data
	{
	return __table_insert(t, key, val);
	}

function table_remove(t: Broker::Data, key: any): Broker::Data
	{
	return __table_remove(t, key);
	}

function table_lookup(t: Broker::Data, key: any): Broker::Data
	{
	return __table_lookup(t, key);
	}

function table_iterator(t: Broker::Data): opaque of Broker::TableIterator
	{
	return __table_iterator(t);
	}

function table_iterator_last(it: opaque of Broker::TableIterator) : bool
	{
	return __table_iterator_last(it);
	}

function table_iterator_next(it: opaque of Broker::TableIterator) : bool
	{
	return __table_iterator_next(it);
	}

function table_iterator_value(it: opaque of Broker::TableIterator): Broker::TableItem
	{
	return __table_iterator_value(it);
	}

function vector_create(): Broker::Data
	{
	return __vector_create();
	}

function vector_clear(v: Broker::Data) : bool
	{
	return __vector_clear(v);
	}

function vector_size(v: Broker::Data): count
	{
	return __vector_size(v);
	}

function vector_insert(v: Broker::Data, idx: count, d: any) : bool
	{
	return __vector_insert(v, idx, d);
	}

function vector_replace(v: Broker::Data, idx: count, d: any): Broker::Data
	{
	return __vector_replace(v, idx, d);
	}

function vector_remove(v: Broker::Data, idx: count): Broker::Data
	{
	return __vector_remove(v, idx);
	}

function vector_lookup(v: Broker::Data, idx: count): Broker::Data
	{
	return __vector_lookup(v, idx);
	}

function vector_iterator(v: Broker::Data): opaque of Broker::VectorIterator
	{
	return __vector_iterator(v);
	}

function vector_iterator_last(it: opaque of Broker::VectorIterator) : bool
	{
	return __vector_iterator_last(it);
	}

function vector_iterator_next(it: opaque of Broker::VectorIterator) : bool
	{
	return __vector_iterator_next(it);
	}

function vector_iterator_value(it: opaque of Broker::VectorIterator): Broker::Data
	{
	return __vector_iterator_value(it);
	}

function record_create(sz: count): Broker::Data
	{
	return __record_create(sz);
	}

function record_size(r: Broker::Data): count
	{
	return __record_size(r);
	}

function record_assign(r: Broker::Data, idx: count, d: any) : bool
	{
	return __record_assign(r, idx, d);
	}

function record_lookup(r: Broker::Data, idx: count): Broker::Data
	{
	return __record_lookup(r, idx);
	}

function record_iterator(r: Broker::Data): opaque of Broker::RecordIterator
	{
	return __record_iterator(r);
	}

function record_iterator_last(it: opaque of Broker::RecordIterator) : bool
	{
	return __record_iterator_last(it);
	}

function record_iterator_next(it: opaque of Broker::RecordIterator) : bool
	{
	return __record_iterator_next(it);
	}

function record_iterator_value(it: opaque of Broker::RecordIterator): Broker::Data
	{
	return __record_iterator_value(it);
	}

