Collaboration diagram for SHORE Storage Manager Application Programming Interface (SSM API):
![]() |
The storage manager stores state information in per-thread variables; for this reason, storage manager methods must be called in the context of a storage manager thread, smthread_t. This means they must be called (directly or indirectly) by the run() method of a class derived from smthread_t. As a result, you must write a class to encapsulate your server functionality, and that class must derive from smthread_t, as described in the following pseudo-code:
main() { // Marshall all the resources needed to get going: // "Open" the sources of work for your server, such as // listening on a network socket, or opening an input // file for reading. // // Start up a storage manager: your_server_thread_t *server = new your_server_thread_t(...); // let the server thread do its thing server->fork(); // wait until it's done server->join(); // clean up delete server; // un-marshall resources (close files, clean up, etc) } // This class creates and destroys a storage manager, // and forks the worker threads that use the storage manager. class \em your_server_thread_t : public smthread_t { your_server_thread_t ( ...sources... ) ; ~your_server_thread_t () ; void run(); // this is virtual in smthread_t }; // This class performs work given to it by a source. // It uses the given storage manager instance to perform that work. class \em your_worker_thread_t : public smthread_t { your_worker_thread_t (ss_m *ssm, ...source... ) ; ~your_worker_thread_t () ; void run(); // this waits for work from its assigned source // (e.g., from terminal input or from a network connection), and // performs the necessary work }; void your_server_thread_t::run() { // marshal resources neeeded for storage manager work // including run-time options (see discussion below). ss_m *ssm = new ss_m(...); // Fork off some number of threads // worker threads that use the instance ssm. // Either pass ssm to these threads' constructors or // make ssm global. for(int i = 0; i < num_threads; i++) { workers[i] = new your_worker_t(ssm, ... source ... ); } // smthreads' run() method is not called until thread is forked. for(int i = 0; i < NUM_THREADS; i++) { workers[i]->fork(); } // Await and join worker threads. Join() returns when thread's // run() method returns. for(int i = 0; i < NUM_THREADS; i++) { workers[i]->join(); } for(int i = 0; i < NUM_THREADS; i++) { delete workers[i]; } delete ssm; // un-marshal (clean up) resources neeeded for storage manager work } // a join() on this thread now returns. *
The storage manager relies heavily on certain programming idioms to make sure return values from all methods are checked. The idioms are encapsulated in preprocessor macros. As a user of the storage manager, you strongly encouraged to use these idioms. Although the use of the macros is optional, perusal of the storage manager source code and examples will be easier if you are aware of them. They are described in Programming Idioms, Significant C Preprocessor Macros, and w_rc.h. Before you spend much time looking at examples, it would be worthwhile to look at the macro definitions in w_rc.h.
The storage manager is parameterized with options and their associated values. The options determine such things as the size of the buffer pool and lock table, the location of the log, lock granularity, certain caching behavior. Most of these have default values, but some options (such as a path name indicating the location of the log) do not have a default value and must be given values at run time.
An options-processing package is provided for this purpose. It handles the parsing of option names and values, which may be given on the command line, or in a file or input stream. Because certain options must be given a value at run-time, the use of this package is not optional: every server must at least create a minimal set of options and give them values. In the above pseudo-code, invoking the run-time options package would be inserted in
your_server_thread_t::run()
main().
The storage manager release comes with small examples illustrating how the options are to be used.
See
With few exceptions, the storage manager does work on behalf of a transaction and the storage manager acquires locks for that transaction, e.g., to read a record, the storage manager acquires read locks and to update a record it acquires write locks. Rather than expect the transaction of interest to be given as an argument to every storage manager method, the storage manager assumes an attachment between a storage manager thread and a transaction. The attachment is not fixed and permanent; rather, a worker thread can choose which transaction it is serving, and can set aside transaction A and proceed to serve transaction B, while another thread can pick up transaction B and do work on its behalf. A thread cannot serve more than one transaction at any time, and, except under limited circumstances, a transaction cannot be served by more than one thread at a time. Through the API, a storage manager thread can :
See Transactions, Locking and Logging for details.
Persistent data are contained in a variety of storage structures (files of records, indexes, etc.). All data structures reside in volumes, which are mounted. Identifiers for data on the volume contain that volume number. The act of mounting a volume creates the association of the volume number with the path name of a Unix file. OK, that's a lie. The original design of SHORE called for multiple volumes per Unix file, and so the file was associated with a device, and volumes were contained in a device. SHORE never supported multiple volumes on a device, but the device-volume distinction remains. Thus, a server mounts (and formats, if necessary) a device, which is identified by a path name. Then the server creates a volume (numbered), which resides on the device.
See Storage Structures for details about storage structures, and see Identifiers for a description of the identifiers used for storage structures and transactions.
Please refer to the list of modules at the bottom of this page for more information.
When the storage manager is built, its "make" flags are written to a file called
The list of libraries must include -lrt and possibly -lnsl.
#include <sm_vas.h>