Preparing and opening stores
The first step for storing data in memory is to create an instance of a Storage event. You use the Storage event to prepare and open a store to which you can add tables. Storage events define actions that do the following:
Request preparation of a store.
Open a store that has been prepared.
Storage events contain no data. All Storage events are alike and exist only to provide the interface for preparing and opening stores.
If you do not require on-disk persistence, you can prepare a store in memory. If you do require on-disk persistence, you can specify the file that contains (or that you want to contain) the store. Depending on the action you call to open the store, the MemoryStore does one of the following:
Opens the store for read-write access.
Opens the store for read-only access.
Opens the store for read-write access. Create the store if it does not already exist.
Preparation of stores is asynchronous. Actions that prepare stores return an ID immediately. When the MemoryStore completes preparation it enqueues a Finished event that contains this ID. You should define an event listener for this Finished event. The Finished event indicates whether or not preparation was successful.
You can open a store only after receiving a Finished event that indicates successful preparation.
For example, the following code fragment declares a Storage type variable and a Store type variable. It then calls the prepareOrCreate() action on the Storage type variable and saves the returned ID in the Store type variable. The name of the new store is storename and the store will be made persistent by saving it in the example.dat file. Finally, this code fragment declares a Finished event variable and an event listener for a Finished event whose ID matches the ID returned by the preparation request.
using com.apama.memorystore.Storage;
using com.apama.memorystore.Store;
using com.apama.memorystore.Finished;
monitor Test {
Storage storage;
Store store;
action onload() {
integer id := storage.prepareOrCreate("storename", "/tmp/example.dat");
Finished f;
on Finished(id,*,*):f
onStorePrepared(f);
...
}
}
After a store has been successfully prepared, you can open it:
action onStorePrepared(Finished f) {
if not f.success then { log "Whoops"; die; }
store := storage.open("storename");
All subsequent examples assume that the appropriate using statements have been added.
Any monitor instance can open a store after that store has been successfully prepared. However, monitor A has no information about whether or not monitor B has prepared a particular store.
Therefore, each monitor should prepare any store it needs, and then prepare any tables it needs within that store. There is no way to pass Store or Table events from one monitor to another. Multiple monitors can prepare and open the same store or table at the same time.
There are several different actions available for preparing a store:
Storage.prepareInMemory(string name) returns
integer prepares an in-memory store with the name you specify. All tables are empty when prepared for the first time. Persistence requests are ignored and immediately return a successful
Finished event.
Storage.prepare(string name, string filename) returns
integer does the same thing as
Storage.prepareInMemory and it also associates that store with the database file you specify. If there is data in the database file the MemoryStore loads the store with the data from the file when you prepare a table. Persistence requests write changes back to the file. The specified file must exist.
Storage.prepareOrCreate(string name, string filename) returns
integer does the same thing as
Storage.prepare() except that it creates the file if it does not already exist.
Storage.prepareReadOnly(string name, string filename) returns
integer does the same thing as
Storage.prepare and it also opens for read-only access the database file you specify. The MemoryStore will load the store with data from the file when you prepare the table. Persistence requests are refused and return a failure
Finished event
Storage.prepareCorrelatorPersistent(string name) returns
integer prepares a store that the correlator automatically persists. Each time the correlator takes a snapshot, the snapshot includes any correlator-persistent stores along with the contents of those stores.
Storage.prepareDistributed(string name) returns
integer prepares a distributed store which will be available to applications running in a cluster of correlators. The
name argument is a unique identifier that specifies the name of a configured distributed store. For information on adding a distributed store to a project, see
Adding a distributed store.
Suppose a monitor instance calls one of the Storage.prepare() actions and the action is successful. Now suppose another monitor instance calls the same Storage.prepare() variant with the same table name and, if applicable, the same filename, as the previously successful call. The second call does nothing and indicates success immediately. However, if a monitor instance makes a Storage.prepare() call and specifies the same table name as was specified in a previously successful prepare() call, that call fails immediately if at least one of the following is different from the successful call:
The variant of the
prepare() action called
The specified file name or store name (if applicable)
For example, suppose a monitor made the following successful call:
Storage.prepare("foo", "/tmp/foo.dat")
After this call, the only prepare call that can successfully prepare the same table is
Storage.prepare("foo", "/tmp/foo.dat")
The following calls would all fail:
Storage.prepareInMemory("foo")
Storage.prepareOrCreate("foo", "/tmp/foo.dat")
Storage.prepareReadOnly("foo", "/tmp/foo.dat")
Storage.prepare("foo", "/tmp/bar.dat")
If a monitor makes a call to prepare() that matches a prepare action that is in progress, the result is the same as the result of the prepare that is in progress.