Merge lp:~pbeaman/akiban-persistit/sphinxdoc-release-notes into lp:akiban-persistit
- sphinxdoc-release-notes
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Nathan Williams |
Approved revision: | 314 |
Merged at revision: | 312 |
Proposed branch: | lp:~pbeaman/akiban-persistit/sphinxdoc-release-notes |
Merge into: | lp:akiban-persistit |
Diff against target: |
4768 lines (+2646/-1989) 26 files modified
doc/BasicAPI.rst (+332/-0) doc/BasicAPI.txt (+0/-320) doc/Configuration.rst (+273/-0) doc/Configuration.txt (+0/-246) doc/GettingStarted.rst (+270/-0) doc/GettingStarted.txt (+0/-255) doc/Management.rst (+446/-0) doc/Management.txt (+0/-360) doc/Miscellaneous.rst (+36/-0) doc/Miscellaneous.txt (+0/-32) doc/PhysicalStorage.rst (+142/-0) doc/PhysicalStorage.txt (+0/-126) doc/ReleaseNotes.rst (+84/-0) doc/Security.rst (+93/-0) doc/Security.txt (+0/-91) doc/Serialization.rst (+250/-0) doc/Serialization.txt (+0/-246) doc/TOC.txt (+0/-19) doc/Transactions.rst (+200/-0) doc/Transactions.txt (+0/-179) doc/build/build-doc.sh (+25/-8) doc/build/build-doc.sh.orig (+48/-0) doc/build/src/SphinxDocPrep.java (+147/-0) doc/conf.py (+285/-0) doc/index.rst (+15/-0) doc/overview-summary.txt (+0/-107) |
To merge this branch: | bzr merge lp:~pbeaman/akiban-persistit/sphinxdoc-release-notes |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Nathan Williams | Approve | ||
Review via email: mp+108031@code.launchpad.net |
Commit message
Description of the change
This branch includes some work previously done but never proposed in lp:~pbeaman/akiban-persistit/sphinxdoc-1, and new work on the release notes.
This branch only changes the doc directory.
Changes:
Convert all the asciidoc source files to sphinx. Files xxx.txt are removed and different files xxx.rst are added with formatting encoded for sphinx.
Content edits in some files resulting from the change.
New doc/build/build.sh script which now places all output in the target directory.
With these changes you must have sphinx (v 1.1.3) to run the build process. A new Java program, SphinxDocPrep does the appropriate text replacements in the sphinx-formatted files. The result of running build.sh is:
target/
target/
target/
Preview Diff
1 | === added file 'doc/BasicAPI.rst' |
2 | --- doc/BasicAPI.rst 1970-01-01 00:00:00 +0000 |
3 | +++ doc/BasicAPI.rst 2012-05-30 18:23:19 +0000 |
4 | @@ -0,0 +1,332 @@ |
5 | +.. _Basic-API: |
6 | + |
7 | +Basic API |
8 | +========= |
9 | + |
10 | +Akiban Persistit stores data as key-value pairs in highly optimized B-Tree. (Actually, implements `B-Link Tree <http://www.cs.cornell.edu/courses/cs4411/2009sp/blink.pdf>`_ trees for greater concurrency). Like a Java Map implementation, Persistit associates at most one value with each unique instance of a Key value. |
11 | + |
12 | +Persistit provides classes and methods to access and modify keys and their associated values. Application code calls Persistit API methods to store, fetch, traverse and remove keys and records to and from the database. |
13 | + |
14 | +Persistit permits efficient multi-threaded concurrent access to database volumes. It is designed to minimize contention for critical resources and to maximize throughput on multi-processor machines. Concurrent ACID transactions are supported with multi-value concurrency control (MVCC). |
15 | + |
16 | +The Persistit Instance |
17 | +---------------------- |
18 | + |
19 | +To access Persistit, the application first constructs an instance of the ``com.persistit.Persistit`` class and initializes it. This instance is the keystone of all subsequent operations. It holds references to the buffers, maps, transaction contexts and other structures needed to access B-trees. The life cycle of a Persistit instance should be managed as follows: |
20 | + |
21 | +.. code-block:: java |
22 | + |
23 | + final Persistit db = new Persistit(); |
24 | + // |
25 | + // register any Coder and Renderer instances before initialization |
26 | + // |
27 | + db.initialize(configProperties); |
28 | + try { |
29 | + // do application work |
30 | + } finally { |
31 | + db.close(); |
32 | + } |
33 | + |
34 | +The ``configProperties`` describe the memory allocation, initial set of volumes, the journal, and other settings needed to get Persistit started. See :ref:`Configuration` for details. |
35 | + |
36 | +The ``com.persistit.Persistit#close`` method gracefully flushes all modified data to disk, stops background threads and unregisters JMX MBeans. |
37 | + |
38 | +.. note:: |
39 | + |
40 | + The Persistit background threads are not daemon threads, so if your application returns |
41 | + from its static main method without calling ``close``, the JVM will not automatically exit. |
42 | + |
43 | +Although normal shutdown should always invoke ``close``, Persistit is designed to recover a consistent database state in the event of an abrupt shutdown or crash. See :ref:`Recovery`. |
44 | + |
45 | +.. _Key: |
46 | + |
47 | +Key |
48 | +--- |
49 | + |
50 | +The content of a ``com.persistit.Key`` is the unique identifier for a key/value pair within a tree. Internally a ``Key`` contains an array of bytes that constitute the physical identity of the key/value pair within a tree. Logically, a key consists of a sequence of zero or more Java values, each of which is called a *key segment*. |
51 | + |
52 | +The following value types are implicitly supported in keys:: |
53 | + |
54 | + null |
55 | + boolean (and Boolean) |
56 | + byte (and Byte) |
57 | + short (and Short) |
58 | + char (and Character) |
59 | + int (and Integer) |
60 | + long (and Long) |
61 | + float (and Float) |
62 | + double (and Double) |
63 | + java.lang.String |
64 | + java.math.BigInteger |
65 | + java.math.BigDecimal |
66 | + java.util.Date |
67 | + byte[] |
68 | + |
69 | +In addition, you may register custom implementations of the ``com.persistit.encoding.KeyCoder`` interface to support encoding of other object classes. By default, String values are encoded in UTF-8 format. |
70 | + |
71 | +Appending and Decoding Key Segments |
72 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
73 | + |
74 | +The ``Key`` class provides methods to encode and decode each of these types to and from a key segment. For each type listed above, there is an ``append`` method, a ``to`` method and a ``decode`` method. For example, for the long type, there are methods |
75 | + |
76 | +.. code-block:: java |
77 | + |
78 | + public void append(long v) |
79 | + public void to(long v) |
80 | + public long decodeLong() |
81 | + |
82 | +The ``to`` methods replaces the final key segment with a different value (unless the key is empty, in which case it works the same as ``append``). |
83 | + |
84 | +For example: |
85 | + |
86 | +.. code-block:: java |
87 | + |
88 | + key.clear(); // clear any previous key segments |
89 | + key.append("Atlantic"); // append segment "Atlantic" |
90 | + key.to("Pacific"); // replace "Atlantic" with "Pacific" |
91 | + key.reset(); // reset index to beginning |
92 | + String s = key.decode(); // s contains "Pacific" |
93 | + |
94 | +The Key class also provides methods to encode and decode Object values to and from a key. Strings, Dates, objects of the corresponding wrapper classes for the primitive types listed above, and objects supported by registered instances of ``com.persistit.encoding.KeyCoder`` are permitted. Primitive values are automatically boxed and unboxed as needed. The following code fragment demonstrates key manipulation with automatic conversion of primitive types and their wrappers. |
95 | + |
96 | +.. code-block:: java |
97 | + |
98 | + key.clear(); // clear any previous key segments |
99 | + key.append(new Integer(1234)); |
100 | + key.append("Atlantic"); |
101 | + key.append(1.23d); |
102 | + key.reset(); // reset index to beginning for decoding |
103 | + int v = key.decodeInt(); // v will be 1234 |
104 | + String s = (String)key.decode(); // s will be "Atlantic" |
105 | + Double d = (Double)decode(); // d will be 1.23d as a Double |
106 | + |
107 | +In this code segment, an object of type Integer is appended to the key’s value sequence, and then the same value is later decoded as a primitive int value. A String is appended and then decoded into a String. Finally, a primitive double value is appended and then decoded as an object of class Double. |
108 | + |
109 | +The maximum size of a serialized ``Key`` is 2,047 bytes. |
110 | + |
111 | +For further information, see ``com.persistit.Key``. |
112 | + |
113 | + |
114 | +.. _Value: |
115 | + |
116 | +Value |
117 | +----- |
118 | + |
119 | +A ``com.persistit.Value`` object holds a value. Unlike keys, Value objects have no restriction on the types of data they can represent, and they can hold much larger objects. In particular, a Value may contain null, any of the primitive types, or an object of any class. |
120 | + |
121 | +The backing store of a ``Value`` is a byte array that is written to a B-Tree data page, or in the case of a long record, multiple pages. The ``com.persistit.Value#put`` method variants encode (serialize) a Java primitive or Object value into the backing store, and the ``com.persistit.Value#get`` method variants decode (deserialize) the value. |
122 | + |
123 | +For example, in ``HelloWorld.java``, the line |
124 | + |
125 | +.. code-block:: java |
126 | + |
127 | + dbex.getValue().put("World"); |
128 | + |
129 | +serializes the String “World”, and the expression |
130 | + |
131 | +.. code-block:: java |
132 | + |
133 | + dbex.getValue().get() |
134 | + |
135 | +decodes it. Persistit does not intrinsically cache decoded object values, nor does it track an object's state changes. Each call to the ``get()`` method returns a new instance of the object. However, you can use a ``com.persistit.encoding.ObjectCache`` to cache object values. ``ObjectCache`` is designed specifically to cache objects fetched from Persistit. |
136 | + |
137 | +Value Types |
138 | +^^^^^^^^^^^ |
139 | + |
140 | +``Value`` provides optimized predefined representations for the following types:: |
141 | + |
142 | + null |
143 | + all primitive types |
144 | + all arrays |
145 | + java.math.BigInteger |
146 | + java.math.BigDecimal |
147 | + java.lang.String |
148 | + java.util.Date |
149 | + |
150 | +In general, Persistit uses one of four mechanisms to encode a Java value into a Value object: |
151 | + |
152 | +- If the value is one of the predefined types listed above, Persistit uses its own internal serialization logic. |
153 | +- If there is a registered ``com.persistit.encoding.ValueCoder`` for the object's class, Persistit delegates to it. |
154 | +- If enabled, Persistit uses an accelerated serialization/deserialization mechanism to encode and decode objects. |
155 | +- Otherwise, for classes that implement java.io.Serializable, Persistit attempts to perform default Java serialization and deserialization. |
156 | + |
157 | +A Value may also be in the undefined state, which results from performing a fetch operation on a key for which no value is present in the database. The undefined state is distinct from the value ``null`` and can be tested with the ``isDefined()`` method. |
158 | + |
159 | +See :ref:`Serialization` for additional information. |
160 | + |
161 | +Large Values |
162 | +^^^^^^^^^^^^ |
163 | + |
164 | +Persistit stores large values, in the current version up to 64MB in size. For example, it is possible to store an image’s backing bytes as a single value in the database. The size of the value to be stored is constrained by available heap memory; the entire value must be able to be serialized into an in-memory byte array in order for Persistit to store or retrieve it. Use ``com.persistit.Value#setMaximumSize`` to specify a the size constraint. Large values are broken up across multiple data pages and are not necessarily stored in contiguous file areas. |
165 | + |
166 | +The definition of “large” depends on the configuration properties. for example, for a volume with a page size of 16K bytes the threshold occurs at 6,108 bytes. A value having a serialized size smaller than this is stored in a single data page while a larger value is broken up and stored in multiple pages. For a smaller pages size the threshold is lower. |
167 | + |
168 | +On occasion it may be desirable to fetch only part of a large value. For example, it may be useful to extract summary information from the beginning of a the backing byte array for an Image. Variants versions of the ``fetch`` and ``traverse`` accept a minimum byte count parameter. When these methods are used only the specified minimum number bytes of the backing store are retrieved from the database. This technique can prevent Persistit from reading large numbers of pages from the disk in order to examine only a small portion of the record. |
169 | + |
170 | +.. _Exchange: |
171 | + |
172 | +Exchange |
173 | +-------- |
174 | + |
175 | +The primary low-level interface for interacting with Persistit is ``com.persistit.Exchange``. The Exchange class provides all methods for storing, deleting, fetching and traversing key/value pairs. These methods are summarized here and described in detail in the Javadoc API documentation. |
176 | + |
177 | +An Exchange instance contains references to a ``Key`` and a ``Value``. The methods ``com.persistit.Exchange.getKey()`` and ``com.persistit.Exchange.getValue()`` access these instances. |
178 | + |
179 | +To construct an Exchange you specify a Volume (or alias) and a tree name in its constructor. The constructor will optionally create a new tree in that Volume if a tree having the specified name has not already been created. An application may construct an arbitrary number of Exchange objects. Creating a new Exchange has no effect on the database if the specified tree already exists. Tree creation is thread-safe: multiple threads concurrently constructing Exchanges using the same Tree name will safely result in the creation of only one new tree. |
180 | + |
181 | +An Exchange is a moderately complex object that can consume tens of kilobytes to megabytes (depending on the sizes of the Key and Value) of heap space. Memory-constrained applications should construct Exchanges in moderatation. |
182 | + |
183 | +Persistit offers Exchange pooling to avoid rapidly creating and destroying Exchange objects in multi-threaded applications. An application may use the ``com.persistit.Persistit#getExchange`` and ``com.persistit.Persistit#releaseExchange`` methods to take and return an Exchange from and to a thread-local pool. |
184 | + |
185 | +An Exchange internally maintains some optimization information such that references to nearby Keys within a tree are accelerated. Performance may benefit from using a different Exchange for each area of the Tree being accessed. |
186 | + |
187 | +Concurrent Operations on Exchanges |
188 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
189 | + |
190 | +Although the underlying Persistit database is designed for highly concurrent multi-threaded operation, the ``Exchange`` class and its associated ``Key`` and ``Value`` instances are *not* thread-safe. Each thread should acquire and use its own Exchange objects when accessing the database. Nonetheless, multiple threads can execute database operations on overlapping data concurrently using their thread-private ``Exchange`` instances. |
191 | + |
192 | +Because Persistit permits concurrent operations by multiple threads, there is no guarantee that the underlying database will remain unchanged after an Exchange fetches or modifies its data. However, each operation on an Exchange is atomic, meaning that the inputs and outputs of each method are consistent with some valid state of the underlying Persistit backing store at some instant in time. The Exchange’s Value and Key objects represent that consistent state even if another thread subsequently modifies the database. Transactions, described below, allow multiple database operations to be performed atomically and consistently. |
193 | + |
194 | +Exchange API |
195 | +^^^^^^^^^^^^ |
196 | + |
197 | +An Exchange has permanent references to a ``com.persistit.Key`` and a ``com.persistit.Value``. Typically you work with an Exchange in one of the following patterns: |
198 | + |
199 | +- Modify the Key, perform a ``fetch`` operation, and extract the Value. |
200 | +- Modify the Key, modify the Value, and then perform a ``store`` operation. |
201 | +- Modify the Key, and then perform a ``remove`` operation. |
202 | +- Optionally modify the Key, perform a ``traverse`` operation, then read the resulting Key and/or Value. |
203 | + |
204 | +These four methods, plus a few other methods listed here, are the primary low-level interface to the database. Semantics are as follows: |
205 | + |
206 | +``fetch`` |
207 | + Reads the stored value associated with this Exchange's Key and modifies the Exchange’s Value to reflect that value. |
208 | +``store`` |
209 | + Inserts or replaces the key/value pair for the specified key in the Tree either by replacing the former value, if there was one, or inserting a new value. |
210 | +``fetchAndStore`` |
211 | + Reads and then replaces the stored value. Upon completion, Value reflects the formerly stored value for the current Key. This operation is atomic. |
212 | +``remove``, ``removeAll``, ``removeKeyRange`` |
213 | + Removes key/value pairs from the Tree. Versions of this method specify either a single key or a range of keys to be removed. |
214 | +``fetchAndRemove`` |
215 | + Fetches and then removes the stored value. Upon completion, Value reflects the formerly stored value for the current Key. This operation is atomic. |
216 | +``traverse``, ``next``, ``previous`` |
217 | + Modifies the Exchange’s Key and Value to reflect a successor or predecessor key within the tree. See ``com.persistit.Key`` for detailed information on the order of traversal. |
218 | +``hasNext``, ``hasPrevious`` |
219 | + Indicates, without modifying the Exchange’s Value or Key objects, whether there is a successor or predecessor key in the Tree. |
220 | +``hasChildren`` |
221 | + Indicates whether there are records having keys that are logical children. A *logical child* of some key *P* is any key that can be constructed by appending one or more key segments to *P*. |
222 | + |
223 | +For convenience, Exchange delegates ``append`` and ``to`` methods to ``com.persistit.Key``. For example, Exchange provides the following methods that delegate to the identically named methods of Key : |
224 | + |
225 | +.. code-block:: java |
226 | + |
227 | + public Exchange append(long v) |
228 | + public Exchange append(String v) |
229 | + ... |
230 | + |
231 | +To allow code call-chaining these methods of Exchange return the same Exchange. For example, it is valid to write code such as |
232 | + |
233 | +.. code-block:: java |
234 | + |
235 | + exchange.clear().append(" Pacific").append("Ocean").append(123).fetch(); |
236 | + |
237 | +This example fetches the value associated with the concatenated key |
238 | +``{“Pacific”, ”Ocean”, 123}``. |
239 | + |
240 | +Exchange also delegates other key manipulation methods. (See ``com.persistit.Exchange`` for detailed API documentation.) |
241 | + |
242 | +Traversing and Querying Collections of Data |
243 | +------------------------------------------- |
244 | + |
245 | +An Exchange provides a number of methods for traversing a collection of records in the Persistit database. These include variations of the ``com.persistit.Exchange#traverse``, ``com.persistit.Exchange#next`` and ``com.persistit.Exchange#previous``. For all of these methods, Persistit does two things: it modifies the Exchange's ``Key`` to reflect a new key that is before or after the current key, and it modifies the ``Value`` associated with the Exchange to reflect the database value associated with that key. |
246 | + |
247 | +For example, this code from ``HelloWorld.java`` prints out the key and value of each record in a tree: |
248 | + |
249 | +.. code-block:: java |
250 | + |
251 | + dbex.getKey().to(Key.BEFORE); |
252 | + while (dbex.next()) |
253 | + { |
254 | + System.out.println( |
255 | + dbex.getKey().indexTo(0).decode() + " " + |
256 | + dbex.getValue().get()); |
257 | + } |
258 | + |
259 | +In general, the traversal methods let you find a key in a tree related to the key you supply. In Persistit programs you frequently prime a key value by appending either ``com.persistit.Key#BEFORE`` or ``com.persistit.Key#AFTER``. A key containing either of these special values can never be stored in a tree; these are reserved to represent positions in key traversal order before the first valid key and after the last valid key, respectively. You then invoke next or previous, or any of the other traverse family variants, to enumerate keys within the tree. |
260 | + |
261 | +You can specify whether traversal is *deep* or *shallow*. Deep traversal traverses the logical children (see com.persistit.Key) of a key. Shallow traversal traverses only the logical siblings. |
262 | + |
263 | +.. _KeyFilter: |
264 | + |
265 | +Selecting key values with a KeyFilter |
266 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
267 | + |
268 | +A ``com.persistit.KeyFilter`` defines a subset of all possible key values. For example, a KeyFilter can select keys with certain fixed segment values, sets of values or ranges of values. Calling ``traverse``, ``next`` or ``previous`` with a KeyFilter efficiently traverses the subset of all keys in a Tree that match the filter. |
269 | + |
270 | +You construct a KeyFilter either by adding selection terms to it, or by calling the ``com.persistit.KeyParser#parseKeyFilter`` method of the ``com.persistit.KeyParser`` class to construct one from a string representation. |
271 | + |
272 | +Use of a KeyFilter is illustrated by the following code fragment: |
273 | + |
274 | +.. code-block:: java |
275 | + |
276 | + Exchange ex = new Exchange("myVolume", "myTree", true); |
277 | + KeyFilter kf = new KeyFilter("{\"Bellini\":\"Britten\"}"); |
278 | + ex.append(Key.BEFORE); |
279 | + while (ex.next(kf)){ |
280 | + System.out.println(ex.getKey().reset().decodeString()); |
281 | + } |
282 | + |
283 | +This simple example emits the string-valued keys within Tree “myTree” whose values fall alphabetically between “Bellini” and “Britten”, inclusive. |
284 | + |
285 | + |
286 | +You will find an example with a KeyFilter in the examples/FindFileDemo directory. |
287 | + |
288 | +.. _PersistitMap: |
289 | + |
290 | +PersistitMap |
291 | +------------ |
292 | + |
293 | +In addition to low-level access methods on keys and values, Persistit provides ``com.persistit.PersistitMap``, which implements the ``java.util.SortedMap`` interface. PersistitMap uses the Persistit database as a backing store so that key/value pairs are persistent, potentially shared with all threads, and limited in number only by disk storage. |
294 | + |
295 | +Keys and Values for PersistitMap must conform to the constraints described above under :ref:`Key` and :ref:`Value`. |
296 | + |
297 | +The constructor for PersistitMap takes an Exchange as its sole parameter. All key/value pairs of the Map are stored within the tree identified by this Exchange. The Key supplied by the Exchange becomes the root of a logical tree. For example: |
298 | + |
299 | +.. code-block:: java |
300 | + |
301 | + Exchange ex = new Exchange("myVolume", "myTree", true); |
302 | + ex.append("USA").append("MA"); |
303 | + PersistitMap<String, String> map = new PersistitMap<String, String>(ex); |
304 | + map.put("Boston", "Hub"); |
305 | + |
306 | +places a key/value pair into Tree “myTree” with the concatenated key ``{"USA ","MA","Boston"}`` and a value ``"Hub"``. |
307 | + |
308 | +Generally the expected behavior for an Iterator on a Map collection view is to throw a ``ConcurrentModificationException`` if the underlying collection changes. This is known as “fail-fast” behavior. PersistitMap implements this behavior by throwing a ``ConcurrentModificationException`` in the event the Tree containing the map changes after the Iterator is constructed. |
309 | + |
310 | +However, sometimes it may be desirable to use PersistitMap and its collections view interfaces to iterate across changing data, especially for large databases. PersistitMap provides the method ``com.persistit.PersistitMap#setAllowConcurrentModification`` to control whether changes made by other threads are permitted. By default, concurrent modifications are not allowed. |
311 | + |
312 | +.. note:: When ``PersistitMap`` is used within a transaction updates generated by other concurrent transactions are not visible and |
313 | + therefore cannot cause a ConcurrentModificationException. However, to avoid unpredictable results an Iterator created within the scope |
314 | + of a transaction must be used only within that transaction. |
315 | + |
316 | + |
317 | +Exceptions in PersistitMap |
318 | +^^^^^^^^^^^^^^^^^^^^^^^^^^ |
319 | + |
320 | +Persistit operations throw a variety of exceptions that are subclasses of ``com.persistit.exception.PersistitException``. However, the methods of the SortedMap interface do not permit arbitrary checked exceptions to be thrown. Therefore, PersistitMap wraps any PersistitException generated by the underlying database methods within a ``com.persistit.PersistitMap.PersistitMapException``. This exception is unchecked and can therefore be thrown by methods of the Map interface. Applications using PersistitMap should catch and handle PersistitMap.PersistitMapException. |
321 | + |
322 | +Applying a KeyFilter to a PersistitMap Iterator |
323 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
324 | + |
325 | +You can specify a ``com.persistit.KeyFilter`` for the Iterator returned by the ``keySet()``, ``entrySet()`` and ``values()`` methods of ``com.persistit.PersistitMap``. The KeyFilter restricts the range of keys traversed by the Iterator. To set the KeyFilter, you must cast the Iterator to the inner class PersistitMap.ExchangeIterator, as shown here: |
326 | + |
327 | +.. code-block:: java |
328 | + |
329 | + PersistitMap map = new PersistitMap(exchange); |
330 | + PersistitMap.ExchangeIterator iterator = |
331 | + (PersistitMap.ExchangeIterator)map.entrySet().iterator(); |
332 | + iterator.setFilterTerm(KeyFilter.rangeTerm("A", "M")); |
333 | + |
334 | +In this example, the iterator will only access String-valued keys between “A” and “M”. |
335 | + |
336 | + |
337 | |
338 | === removed file 'doc/BasicAPI.txt' |
339 | --- doc/BasicAPI.txt 2012-04-30 22:09:31 +0000 |
340 | +++ doc/BasicAPI.txt 1970-01-01 00:00:00 +0000 |
341 | @@ -1,320 +0,0 @@ |
342 | -[[BasicAPI]] |
343 | -= Basic API |
344 | - |
345 | -Akiban Persistit stores data as key-value pairs in highly optimized B-Tree footnote:[Technically, Persistit implements http://www.cs.cornell.edu/courses/cs4411/2009sp/blink.pdf[B-Link] trees for greater concurrency]. Like a Java Map implementation, Persistit associates at most one value with each unique instance of a Key value. |
346 | - |
347 | -Persistit provides classes and methods to access and modify keys and their associated values. Application code calls Persistit API methods to store, fetch, traverse and remove keys and records to and from the database. |
348 | - |
349 | -Persistit permits efficient multi-threaded concurrent access to database volumes. It is designed to minimize contention for critical resources and to maximize throughput on multi-processor machines. Concurrent ACID transactions are supported with multi-value concurrency control (MVCC). |
350 | - |
351 | -== The Persistit Instance |
352 | - |
353 | -To access Persistit, the application first constructs an instance of the +com.persistit.Persistit+ class and initializes it. This instance is the keystone of all subsequent operations. It holds references to the buffers, maps, transaction contexts and other structures needed to access B-trees. The life cycle of a Persistit instance should be managed as follows: |
354 | - |
355 | -[source,java] |
356 | ----- |
357 | -final Persistit db = new Persistit(); |
358 | -// |
359 | -// register any Coder and Renderer instances before initialization |
360 | -// |
361 | -db.initialize(configProperties); |
362 | -try { |
363 | - // do application work |
364 | -} finally { |
365 | - db.close(); |
366 | -} |
367 | ----- |
368 | - |
369 | -The +configProperties+ describe the memory allocation, initial set of volumes, the journal, and other settings needed to get Persistit started. See <<Configuration>> for details. |
370 | - |
371 | -The +com.persistit.Persistit#close+ method gracefully flushes all modified data to disk, stops background threads and unregisters JMX MBeans. |
372 | -**** |
373 | -The Persistit background threads are not daemon threads, so if your application returns from its static main method without calling +close+, the JVM will not automically exit. |
374 | -**** |
375 | - |
376 | -Although normal shutdown should always invoke +close+, Persistit is designed to recover a consistent database state in the event of an abrupt shutdown or crash. See <<Recovery>>. |
377 | - |
378 | -[[Key]] |
379 | -== Key |
380 | - |
381 | -The content of a +com.persistit.Key+ is the unique identifier for a key/value pair within a tree. Internally a +Key+ contains an array of bytes that constitute the physical identity of the key/value pair within a tree. Logically, a key consists of a sequence of zero or more Java values, each of which is called a _key segment_. |
382 | - |
383 | -The following value types are implicitly supported in keys: |
384 | - |
385 | -.Types Supported in +com.persistit.Key+ |
386 | ----- |
387 | -null |
388 | -boolean (and Boolean) |
389 | -byte (and Byte) |
390 | -short (and Short) |
391 | -char (and Character) |
392 | -int (and Integer) |
393 | -long (and Long) |
394 | -float (and Float) |
395 | -double (and Double) |
396 | -java.lang.String |
397 | -java.math.BigInteger |
398 | -java.math.BigDecimal |
399 | -java.util.Date |
400 | -byte[] |
401 | ----- |
402 | - |
403 | -In addition, you may register custom implementations of the +com.persistit.encoding.KeyCoder+ interface to support encoding of other object classes. By default, String values are encoded in UTF-8 format. |
404 | -**** |
405 | -TODO: Collation |
406 | -**** |
407 | - |
408 | -=== Appending and Decoding Key Segments |
409 | - |
410 | -The +Key+ class provides methods to encode and decode each of these types to and from a key segment. For each type listed above, there is an +append+ method, a +to+ method and a +decode+ method. For example, for the long type, there are methods |
411 | - |
412 | -[source,java] |
413 | ----- |
414 | -public void append(long v) |
415 | -public void to(long v) |
416 | -public long decodeLong() |
417 | ----- |
418 | - |
419 | -The +to+ methods replaces the final key segment with a different value (unless the key is empty, in which case it works the same as +append+). |
420 | - |
421 | -For example: |
422 | - |
423 | -[source,java] |
424 | ----- |
425 | -key.clear(); // clear any previous key segments |
426 | -key.append("Atlantic"); // append segment "Atlantic" |
427 | -key.to("Pacific"); // replace "Atlantic" with "Pacific" |
428 | -key.reset(); // reset index to beginning |
429 | -String s = key.decode(); // s contains "Pacific" |
430 | ----- |
431 | - |
432 | -The Key class also provides methods to encode and decode Object values to and from a key. Strings, Dates, objects of the corresponding wrapper classes for the primitive types listed above, and objects supported by registered instances of +com.persistit.encoding.KeyCoder+ are permitted. Primitive values are automatically boxed and unboxed as needed. The following code fragment demonstrates key manipulation with automatic conversion of primitive types and their wrappers. |
433 | - |
434 | -[source,java] |
435 | ----- |
436 | -key.clear(); // clear any previous key segments |
437 | -key.append(new Integer(1234)); |
438 | -key.append("Atlantic"); |
439 | -key.append(1.23d); |
440 | -key.reset(); // reset index to beginning for decoding |
441 | -int v = key.decodeInt(); // v will be 1234 |
442 | -String s = (String)key.decode(); // s will be "Atlantic" |
443 | -Double d = (Double)decode(); // d will be 1.23d as a Double |
444 | ----- |
445 | - |
446 | -In this code segment, an object of type Integer is appended to the key’s value sequence, and then the same value is later decoded as a primitive int value. A String is appended and then decoded into a String. Finally, a primitive double value is appended and then decoded as an object of class Double. |
447 | - |
448 | -The maximum size of a serialized +Key+ is 2,047 bytes. |
449 | - |
450 | -For further information, see +com.persistit.Key+. |
451 | - |
452 | - |
453 | -[[Value]] |
454 | -== Value |
455 | - |
456 | -A +com.persistit.Value+ object holds a value. Unlike keys, Value objects have no restriction on the types of data they can represent, and they can hold much larger objects. In particular, a Value may contain null, any of the primitive types, or an object of any class. |
457 | - |
458 | -The backing store of a +Value+ is a byte array that is written to a B-Tree data page, or in the case of a long record, multiple pages. The +com.persistit.Value#put+ method variants encode (serialize) a Java primitive or Object value into the backing store, and the +com.persistit.Value#get+ method variants decode (deserialize) the value. |
459 | - |
460 | -For example, in +HelloWorld.java+, the line |
461 | - |
462 | -[source,java] |
463 | ----- |
464 | -dbex.getValue().put("World"); |
465 | ----- |
466 | - |
467 | -serializes the String “World”, and the expression |
468 | - |
469 | -[source,java] |
470 | ----- |
471 | -dbex.getValue().get() |
472 | ----- |
473 | - |
474 | -decodes it. Persistit does not intrinsically cache decoded object values, nor does it track an object's state changes. Each call to the +get()+ method returns a new instance of the object. However, you can use a +com.persistit.encoding.ObjectCache+ to cache object values. +ObjectCache+ is designed specifically to cache objects fetched from Persistit. |
475 | - |
476 | -=== Value Types |
477 | - |
478 | -+Value+ provides optimized predefined representations for the following types: |
479 | - |
480 | -.Types Implicitly Supported by +com.persistit.Value+ |
481 | ----- |
482 | -null |
483 | -all primitive types |
484 | -all arrays |
485 | -java.math.BigInteger |
486 | -java.math.BigDecimal |
487 | -java.lang.String |
488 | -java.util.Date |
489 | ----- |
490 | -In general, Persistit uses one of four mechanisms to encode a Java value into a Value object: |
491 | - |
492 | -- If the value is one of the predefined types listed above, Persistit uses its own internal serialization logic. |
493 | -- If there is a registered +com.persistit.encoding.ValueCoder+ for the object's class, Persistit delegates to it. |
494 | -- If enabled, Persistit uses an accelerated serialization/deserialization mechanism to encode and decode objects. |
495 | -- Otherwise, for classes that implement java.io.Serializable, Persistit attempts to perform default Java serialization and deserialization. |
496 | - |
497 | -A Value may also be in the undefined state, which results from performing a fetch operation on a key for which no value is present in the database. The undefined state is distinct from the value +null+ and can be tested with the +isDefined()+ method. |
498 | - |
499 | -See <<Serialization>> for additional information. |
500 | - |
501 | -=== Large Values |
502 | - |
503 | -Persistit stores large values, in the current version up to 64MB in size. For example, it is possible to store an image’s backing bytes as a single value in the database. The size of the value to be stored is constrained by available heap memory; the entire value must be able to be serialized into an in-memory byte array in order for Persistit to store or retrieve it. Use +com.persistit.Value#setMaximumSize+ to specify a the size constraint. Large values are broken up across multiple data pages and are not necessarily stored in contiguous file areas. |
504 | - |
505 | -The definition of “large” depends on the configuration properties. for example, for a volume with a page size of 16K bytes the threshold occurs at 6,108 bytes. A value having a serialized size smaller than this is stored in a single data page while a larger value is broken up and stored in multiple pages. For a smaller pages size the threshold is lower. |
506 | - |
507 | -On occasion it may be desirable to fetch only part of a large value. For example, it may be useful to extract summary information from the beginning of a the backing byte array for an Image. Variants versions of the +fetch+ and +traverse+ accept a minimum byte count parameter. When these methods are used only the specified minimum number bytes of the backing store are retrieved from the database. This technique can prevent Persistit from reading large numbers of pages from the disk in order to examine only a small portion of the record. |
508 | - |
509 | -[[Exchange]] |
510 | -== Exchange |
511 | - |
512 | -The primary low-level interface for interacting with Persistit is +com.persistit.Exchange+. The Exchange class provides all methods for storing, deleting, fetching and traversing key/value pairs. These methods are summarized here and described in detail in the Javadoc API documentation. |
513 | - |
514 | -An Exchange instance contains references to a +Key+ and a +Value+. The methods +com.persistit.Exchange.getKey()+ and +com.persistit.Exchange.getValue()+ access these instances. |
515 | - |
516 | -To construct an Exchange you specify a Volume (or alias) and a tree name in its constructor. The constructor will optionally create a new tree in that Volume if a tree having the specified name has not already been created. An application may construct an arbitrary number of Exchange objects. Creating a new Exchange has no effect on the database if the specified tree already exists. Tree creation is thread-safe: multiple threads concurrently constructing Exchanges using the same Tree name will safely result in the creation of only one new tree. |
517 | - |
518 | -An Exchange is a moderately complex object that can consume tens of kilobytes to megabytes (depending on the sizes of the Key and Value) of heap space. Memory-constrained applications should construct Exchanges in moderatation. |
519 | - |
520 | -Persistit offers Exchange pooling to avoid rapidly creating and destroying Exchange objects in multi-threaded applications. An application may use the +com.persistit.Persistit#getExchange+ and +com.persistit.Persistit#releaseExchange+ methods to take and return an Exchange from and to a thread-local pool. |
521 | - |
522 | -An Exchange internally maintains some optimization information such that references to nearby Keys within a tree are accelerated. Performance may benefit from using a different Exchange for each area of the Tree being accessed. |
523 | - |
524 | -=== Concurrent Operations on Exchanges |
525 | - |
526 | -Although the underlying Persistit database is designed for highly concurrent multi-threaded operation, the +Exchange+ class and its associated +Key+ and +Value+ instances are _not_ thread-safe. Each thread should acquire and use its own Exchange objects when accessing the database. Nonetheless, multiple threads can execute database operations on overlapping data concurrently using their thread-private +Exchange+ instances. |
527 | - |
528 | -Because Persistit permits concurrent operations by multiple threads, there is no guarantee that the underlying database will remain unchanged after an Exchange fetches or modifies its data. However, each operation on an Exchange is atomic, meaning that the inputs and outputs of each method are consistent with some valid state of the underlying Persistit backing store at some instant in time. The Exchange’s Value and Key objects represent that consistent state even if another thread subsequently modifies the database. Transactions, described below, allow multiple database operations to be performed atomically and consistently. |
529 | - |
530 | -=== Exchange API |
531 | - |
532 | -An Exchange has permanent references to a +com.persistit.Key+ and a +com.persistit.Value+. Typically you work with an Exchange in one of the following patterns: |
533 | - |
534 | -- Modify the Key, perform a +fetch+ operation, and extract the Value. |
535 | -- Modify the Key, modify the Value, and then perform a +store+ operation. |
536 | -- Modify the Key, and then perform a +remove+ operation. |
537 | -- Optionally modify the Key, perform a +traverse+ operation, then read the resulting Key and/or Value. |
538 | - |
539 | -These four methods, plus a few other methods listed here, are the primary low-level interface to the database. Semantics are as follows: |
540 | - |
541 | -[horizontal] |
542 | -+fetch+:: Reads the stored value associated with this Exchange's Key and modifies the Exchange’s Value to reflect that value. |
543 | -+store+:: Inserts or replaces the key/value pair for the specified key in the Tree either by replacing the former value, if there was one, or inserting a new value. |
544 | -+fetchAndStore+:: Reads and then replaces the stored value. Upon completion, Value reflects the formerly stored value for the current Key. This operation is atomic. |
545 | -+remove+, +removeAll+, +removeKeyRange+:: Removes key/value pairs from the Tree. Versions of this method specify either a single key or a range of keys to be removed. |
546 | -+fetchAndRemove+:: Fetches and then removes the stored value. Upon completion, Value reflects the formerly stored value for the current Key. This operation is atomic. |
547 | -+traverse+, +next+, +previous+:: Modifies the Exchange’s Key and Value to reflect a successor or predecessor key within the tree. See +com.persistit.Key+ for detailed information on the order of traversal. |
548 | -+hasNext+, +hasPrevious+:: Indicates, without modifying the Exchange’s Value or Key objects, whether there is a successor or predecessor key in the Tree. |
549 | -+hasChildren+:: Indicates whether there are records having keys that are logical children. A _logical child_of some key _P_ is any key that can be constructed by appending one or more key segments to _P_. |
550 | - |
551 | - |
552 | -For convenience, Exchange delegates +append+ and +to+ methods to +com.persistit.Key+. For example, Exchange provides the following methods that delegate to the identically named methods of Key : |
553 | - |
554 | -[source,java] |
555 | ----- |
556 | -public Exchange append(long v) |
557 | -public Exchange append(String v) |
558 | -... |
559 | ----- |
560 | -To allow code call-chaining these methods of Exchange return the same Exchange. For example, it is valid to write code such as |
561 | - |
562 | -[source,java] |
563 | ----- |
564 | -exchange.clear().append(" Pacific").append("Ocean").append(123).fetch(); |
565 | ----- |
566 | - |
567 | -This example fetches the value associated with the concatenated key |
568 | -+{“Pacific”, ”Ocean”, 123}+. |
569 | - |
570 | -Exchange also delegates other key manipulation methods. (See +com.persistit.Exchange+ for detailed API documentation.) |
571 | - |
572 | -=== Traversing and Querying Collections of Data |
573 | - |
574 | -An Exchange provides a number of methods for traversing a collection of records in the Persistit database. These include variations of the +com.persistit.Exchange#traverse+, +com.persistit.Exchange#next+ and +com.persistit.Exchange#previous+. For all of these methods, Persistit does two things: it modifies the Exchange's +Key+ to reflect a new key that is before or after the current key, and it modifies the +Value+ associated with the Exchange to reflect the database value associated with that key. |
575 | - |
576 | -For example, this code from +HelloWorld.java+ prints out the key and value of each record in a tree: |
577 | - |
578 | -[source,java] |
579 | ----- |
580 | - dbex.getKey().to(Key.BEFORE); |
581 | - while (dbex.next()) |
582 | - { |
583 | - System.out.println( |
584 | - dbex.getKey().indexTo(0).decode() + " " + |
585 | - dbex.getValue().get()); |
586 | - } |
587 | ----- |
588 | - |
589 | -In general, the traversal methods let you find a key in a tree related to the key you supply. In Persistit programs you frequently prime a key value by appending either +com.persistit.Key#BEFORE+ or +com.persistit.Key#AFTER+. A key containing either of these special values can never be stored in a tree; these are reserved to represent positions in key traversal order before the first valid key and after the last valid key, respectively. You then invoke next or previous, or any of the other traverse family variants, to enumerate keys within the tree. |
590 | - |
591 | -You can specify whether traversal is _deep_ or _shallow_. Deep traversal traverses the logical children (see com.persistit.Key) of a key. Shallow traversal traverses only the logical siblings. |
592 | - |
593 | -[[KeyFilter]] |
594 | -=== Selecting key values with a KeyFilter |
595 | - |
596 | -A +com.persistit.KeyFilter+ defines a subset of all possible key values. For example, a KeyFilter can select keys with certain fixed segment values, sets of values or ranges of values. Calling +traverse+, +next+ or +previous+ with a KeyFilter efficiently traverses the subset of all keys in a Tree that match the filter. |
597 | - |
598 | -You construct a KeyFilter either by adding selection terms to it, or by calling the +com.persistit.KeyParser#parseKeyFilter+ method of the +com.persistit.KeyParser+ class to construct one from a string representation. |
599 | - |
600 | -Use of a KeyFilter is illustrated by the following code fragment: |
601 | - |
602 | -[source,java] |
603 | ----- |
604 | -Exchange ex = new Exchange("myVolume", "myTree", true); |
605 | -KeyFilter kf = new KeyFilter("{\"Bellini\":\"Britten\"}"); |
606 | -ex.append(Key.BEFORE); |
607 | -while (ex.next(kf)){ |
608 | - System.out.println(ex.getKey().reset().decodeString()); |
609 | -} |
610 | ----- |
611 | - |
612 | -This simple example emits the string-valued keys within Tree “myTree” whose values fall alphabetically between “Bellini” and “Britten”, inclusive. |
613 | - |
614 | - |
615 | -You will find an example with a KeyFilter in the examples/FindFileDemo directory. |
616 | - |
617 | -[[PersistitMap]] |
618 | -=== PersistitMap |
619 | - |
620 | -In addition to low-level access methods on keys and values, Persistit provides +com.persistit.PersistitMap+, which implements the +java.util.SortedMap+ interface. PersistitMap uses the Persistit database as a backing store so that key/value pairs are persistent, potentially shared with all threads, and limited in number only by disk storage. |
621 | - |
622 | -Keys and Values for PersistitMap must conform to the constraints described above under <<Key>> and <<Value>>. |
623 | - |
624 | -The constructor for PersistitMap takes an Exchange as its sole parameter. All key/value pairs of the Map are stored within the tree identified by this Exchange. The Key supplied by the Exchange becomes the root of a logical tree. For example: |
625 | - |
626 | -[source,java] |
627 | ----- |
628 | -Exchange ex = new Exchange("myVolume", "myTree", true); |
629 | -ex.append("USA").append("MA"); |
630 | -PersistitMap<String, String> map = new PersistitMap<String, String>(ex); |
631 | -map.put("Boston", "Hub"); |
632 | ----- |
633 | - |
634 | -places a key/value pair into Tree “myTree” with the concatenated key +{"USA ","MA","Boston"}+ and a value +"Hub"+. |
635 | - |
636 | -Generally the expected behavior for an Iterator on a Map collection view is to throw a +ConcurrentModificationException+ if the underlying collection changes. This is known as “fail-fast” behavior. PersistitMap implements this behavior by throwing a +ConcurrentModificationException+ in the event the Tree containing the map changes after the Iterator is constructed. |
637 | - |
638 | -However, sometimes it may be desirable to use PersistitMap and its collections view interfaces to iterate across changing data, especially for large databases. PersistitMap provides the method +com.persistit.PersistitMap#setAllowConcurrentModification+ to control whether changes made by other threads are permitted. By default, concurrent modifications are not allowed. |
639 | - |
640 | -NOTE: when +PersistitMap+ is used within a transaction updates generated by other concurrent transactions are not visible and therefore cannot cause a ConcurrentModificationException. However, to avoid unpredictable results an Iterator created within the scope of a transaction must be used only within that transaction. |
641 | - |
642 | - |
643 | -=== Exceptions in PersistitMap |
644 | - |
645 | -Persistit operations throw a variety of exceptions that are subclasses of +com.persistit.exception.PersistitException+. However, the methods of the SortedMap interface do not permit arbitrary checked exceptions to be thrown. Therefore, PersistitMap wraps any PersistitException generated by the underlying database methods within a +com.persistit.PersistitMap.PersistitMapException+. This exception is unchecked and can therefore be thrown by methods of the Map interface. Applications using PersistitMap should catch and handle PersistitMap.PersistitMapException. |
646 | - |
647 | -=== Applying a KeyFilter to a PersistitMap Iterator |
648 | - |
649 | -You can specify a +com.persistit.KeyFilter+ for the Iterator returned by the +keySet()+, +entrySet()+ and +values()+ methods of +com.persistit.PersistitMap+. The KeyFilter restricts the range of keys traversed by the Iterator. To set the KeyFilter, you must cast the Iterator to the inner class PersistitMap.ExchangeIterator, as shown here: |
650 | - |
651 | -[source,java] |
652 | ----- |
653 | - PersistitMap map = new PersistitMap(exchange); |
654 | - PersistitMap.ExchangeIterator iterator = |
655 | - (PersistitMap.ExchangeIterator)map.entrySet().iterator(); |
656 | - iterator.setFilterTerm(KeyFilter.rangeTerm("A", "M")); |
657 | ----- |
658 | - |
659 | -In this example, the iterator will only access String-valued keys between “A” and “M”. |
660 | - |
661 | - |
662 | |
663 | === added file 'doc/Configuration.rst' |
664 | --- doc/Configuration.rst 1970-01-01 00:00:00 +0000 |
665 | +++ doc/Configuration.rst 2012-05-30 18:23:19 +0000 |
666 | @@ -0,0 +1,273 @@ |
667 | +.. _Configuration: |
668 | + |
669 | +Configuration |
670 | +============= |
671 | + |
672 | +To initialize Akiban Persistit the embedding application defines a configuration and then invokes one of the ``com.persistit.Persistit#initialize`` methods. The configuration defines parameters used to determine locations of files, sizes of buffer pool and journal files, policies and other elements required when Persistit starts up. These parameters are managed by the ``com.persistit.Configuration`` class. |
673 | + |
674 | +An application can define the configuration in one of two equivalent ways: |
675 | + |
676 | +- Create a ``com.persistit.Configuration`` instance and set its properties through methods such as ``com.persistit.Configuration#setJournalPath``. |
677 | +- Specify properties by name in a ``java.util.Properties`` instance and then pass the ``Properties`` to a ``Configuration`` constructor. |
678 | + |
679 | +The following code samples show different ways of using the ``com.persistit.Persistit#initialize`` method to configure and start Persistit: |
680 | + |
681 | +.. code-block:: java |
682 | + |
683 | + final Persistit db = new Persistit(); |
684 | + final Properties p = new Properties(); |
685 | + p.setProperty("buffer.count.16384", "1000"); |
686 | + p.setProperty("journalpath", "/home/akiban/data/journal"); |
687 | + ... |
688 | + db.initialize(p); |
689 | + |
690 | +.. code-block:: java |
691 | + |
692 | + final Persistit db = new Persistit(); |
693 | + db.initialize("/home/akiban/my_config.properties"); |
694 | + |
695 | +.. code-block:: java |
696 | + |
697 | + final Persistit db = new Persistit(); |
698 | + final Configuration c = new Configuration(); |
699 | + c.getBufferPoolMap().get(16384).setCount(1000); |
700 | + c.setJournalPath("/home/akiban/data/journal"); |
701 | + ... |
702 | + db.initialize(c); |
703 | + |
704 | +There are three essential elements in a Persistit configuration: |
705 | + |
706 | +- Memory for the buffer pool(s) |
707 | +- Specifications for ``com.persistit.Volume`` instances |
708 | +- Journal file path |
709 | + |
710 | +Configuring the Buffer Pool |
711 | +--------------------------- |
712 | + |
713 | +During initialization Persistit allocates a fixed amount of heap memory for use as buffers. Depending on the application, it is usually desirable to allocate most of a server’s physical memory to the JVM heap (using the ``-Xmx`` and ``-Xms`` JVM options) and then to allocate a large fraction of the heap to Persistit buffers. The buffer pool allocation is determined during initialization and remains constant until the embedding application calls ``com.persistit.Persistit#close`` to release all resources. |
714 | + |
715 | +The number of buffers, and therefore the heap memory consumed, is determined during initialization by the available heap memory and configuration parameters. The heap memory size is obtained from the platform MemoryMXBean which in turn supplies the value given by the ``-Xmx`` JVM property. Configuration parameters are specified by a collection of five ``com.persistit.Configuration.BufferPoolConfiguration`` objects, one for each of the possible buffer sizes 1,024, 2,048, 4,096, 8,192 and 16,384 bytes. The method ``com.persistit.Configuration#getBufferPoolMap(int)`` gets the ``BufferPoolConfiguration`` for a specified buffer size. |
716 | + |
717 | +A ``BufferPoolConfiguration`` contains the following attributes: |
718 | + |
719 | + ``minimumCount`` |
720 | + lower bound on the number of buffers. (Default is zero.) |
721 | + ``maximumCount`` |
722 | + upper bound on the number of buffers. (Default is zero.) |
723 | + ``minimumMemory`` |
724 | + lower bound on memory to allocate. (Default is zero bytes.) |
725 | + ``maximumMemory`` |
726 | + upper bound on memory to allocate. (Default is Long.MAX_VALUE bytes.) |
727 | + ``reservedMemory`` |
728 | + minimum number of bytes to reserve for use other than buffers. (Default is zero.) |
729 | + ``fraction`` |
730 | + floating point value between 0.0f and 1.0f indicating how much of available memory too allocate. (Default is 1.0f.) |
731 | + |
732 | +Persistit uses the following algorithm to determine the number of buffers to allocate for each buffer size: |
733 | + |
734 | +.. code-block:: java |
735 | + |
736 | + memoryToUse = fraction * (maxHeap - reservedMemory) |
737 | + memoryToUse = min(memoryToUse, maximumMemory) |
738 | + bufferCount = memoryToUse / bufferSizeWithOverhead |
739 | + bufferCount = max(minimumCount, min(maximumCount, count)) |
740 | + if (bufferCount * bufferSize > maximumMemory) then FAIL |
741 | + if ((bufferCount + 1) * bufferSize < minimumMemory) then FAIL |
742 | + allocate bufferCount buffers |
743 | + |
744 | +In other words, Persistit computes a buffer count based on the memory parameters, bounds it by ``minimumCount`` and ``maximumCount`` and then checks whether the resulting allocation fits within the memory constraints. Note that ``bufferSizeWithOverhead`` is about 14% larger than the buffer size; the additional memory is reserved for indexing data and other overhead associated with the buffer. |
745 | + |
746 | +Typically an application uses a single buffer size, specifying either an absolute count or memory-based constraints for that size. This can be done by setting the attributes of the appropriate ``BufferPoolConfiguration`` object directly, or using Property values. |
747 | + |
748 | +The property named ``buffer.count.SSSS`` where ``SSSS`` is “1024”, “2048”, “4096”, “8192” or “16384” specifies an absolute count. For example, |
749 | + |
750 | +.. code-block:: java |
751 | + |
752 | + buffer.count.8192 = 10000 |
753 | + |
754 | +causes Persistit to allocate 10,000 buffers of size 8192. |
755 | + |
756 | +The property ``buffer.memory.SSSS`` specifies memory constraints as shown in this example |
757 | + |
758 | +.. code-block:: java |
759 | + |
760 | + buffer.memory.8192 = 512K,20M,4M,0.6 |
761 | + |
762 | +where 512K, 20M, 4M and 0.6 are the ``minimumMemory``, ``maximumMemory``, ``reservedMemory`` and ``fraction``, respectively. |
763 | + |
764 | +The MemoryMXBean supplies as its maximum heap size value the size given by the ``-Xmx`` JVM parameter. |
765 | + |
766 | +Heap Tuning |
767 | +----------- |
768 | + |
769 | +This section pertains to the Oracle HotSpot(tm) Java virtual machine. |
770 | + |
771 | +.. note:: |
772 | + |
773 | + Buffer instances are long-lived objects. To avoid severe garbage collector overhead it is important for all of them |
774 | + to fit in the heap’s tenured generation. This issue becomes especially significant with multi-gigabyte heaps. |
775 | + |
776 | +By default the HotSpot server JVM allocates 1/3 of the heap to the new generation and 2/3 to the tenured generation, meaning that allocating more than 2/3 of the heap to buffers will result in bad performance. |
777 | + |
778 | +You can increase the fraction by specifying ``-XX:NewRatio=N`` where ``N`` indicates the ratio of tenured generation space to new generation space, or by using the ``-Xmn`` parameter to specify an absolute amount of memory for the new generation. Also, setting ``-Xms`` equal to ``-Xmx`` will avoid numerous garbage collection cycles during the start-up process. |
779 | + |
780 | +See [http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html] for further information on tuning the heap and garbage collector for the HotSpot JVM. |
781 | + |
782 | +Multiple Buffer Pools |
783 | +--------------------- |
784 | + |
785 | +In some cases it may be desirable to allocate two or more buffer pools having buffers of different sizes. For example, it may be beneficial to use a large number of small buffers to hold secondary index pages. |
786 | + |
787 | +When specifying multiple memory constraints for multiple buffer pools, the ``fraction`` property applies to the available memory before any buffers are allocated. So, for example, |
788 | + |
789 | +.. code-block:: java |
790 | + |
791 | + buffer.memory.2048=64M,512G,2G,.2 |
792 | + buffer.memory.16384=64M,512G,2G,.5 |
793 | + |
794 | +results in two buffer pools having buffers of size 2,048 bytes and 16,384 bytes, respectively. Assuming that the ``-Xmx`` value is 12G, then 2,048 byte buffers will be allocated to fill 20% of 10GByte, 16,384 byte buffers will be allocated to fill 50% of 10GByte, and approximately 5GByte (30% of 10GByte plus 2GByte reserved) will be available to application code. |
795 | + |
796 | +Configuring Volumes |
797 | +------------------- |
798 | + |
799 | +Persistit creates and/or opens a set of database volume files during start-up. An application can create, open and close additional volumes, but it is often convenient for volumes to be defined in the confiuration, outside of application code. |
800 | + |
801 | +The ``com.persistit.Configuration#getVolumeList`` method returns a List of ``com.persistit.VolumeSpecification`` objects. An application can construct and add new ``VolumeSpecification`` instances to this list before calling ``com.persistit.Persistit#initialize(Configuration)``. Alternatively, the application can define volume specifications as property values using the syntax: |
802 | + |
803 | +``volume.N = path[,attrname[:attrvalue]]...`` |
804 | + |
805 | +where ``N`` is an arbitrary integer, ``path`` is the path specification of the volume file, and ``attrnames`` include: |
806 | + |
807 | +- ``pageSize``: Fixed length unit representing one page. Value must be one of 1024, 2048, 4096, 8192 or 16384. To open and use the Volume, the buffer pool must have available buffers of the same size. |
808 | + |
809 | +- ``create``: Persistit attempts to open an existing volume file with the specified *path*, or create a new one if the file does not exist. |
810 | + |
811 | +- ``createOnly``: Persistit throw a VolumeAlreadyExistsException if the file specified by path already exists. Otherwise it creates a new file with the specified path. |
812 | + |
813 | +- ``readOnly``: Opens a volume in read-only mode. An attempt to modify the volume results in a ReadOnlyVolumeException. |
814 | + |
815 | +- ``initialPages`` or ``initialSize``: Specifies the initial size of the newly created volume file, either as the count of pages or as the size in bytes. |
816 | + |
817 | +- ``extensionPages`` or ``extensionSize``: Specifies the extension size of the newly created volume, either as the count of pages or as the size in bytes. This is the size by which the volume file will expand when the volume needs to be enlarged. |
818 | + |
819 | +- ``maximumPages`` or ``maximumSize``: An upper limit on the number of pages this Volume may hold, either as the count of pages or as the size in bytes. An attempt to further enlarge the Volume will generate a VolumeFullException. |
820 | + |
821 | +- ``alias``: The name of this Volume used in constructing ``Exchange`` instances. If unspecified, the name is the simple file name given in the *path*, not including its dotted suffix. |
822 | + |
823 | +For example:: |
824 | + |
825 | + volume.1=/home/akiban/ffdemo,create,pageSize:16K,\ |
826 | + initialSize:10M,extensionSize:10M,maximumSize:1G |
827 | + |
828 | +specifies a volume having the name “ffdemo” in the /home/akiban directory. A new volume will be created if there is no existing volume file, and when created it will have the initial, extension and maximum sizes of 10MByte, 10MByte and 1GByte, respectively. Its page size will be 16KByte, meaning that the configuration must also have a buffer pool of 16KByte buffers. |
829 | + |
830 | +System Volume |
831 | +------------- |
832 | + |
833 | +One volume in a Persistit configuration must be designated as the system volume. It contains class meta data for objects stored serialized in Persistit Values. When a configuration specifies only one volume, that volume implicitly becomes the system volume by default. However, when a configuration specifies multiple volumes, you must indicate which volume will serve as the system volume. There are two ways to do this. By default, Persistit looks for a unique volume named “_system”. You can simply create a volume whose file name is “_system”. |
834 | + |
835 | +Alternatively, you can specify a system volume name explicitly with the ``sysvolume`` property (or ``com.persistit.Configuration#setSysVolume``). The value is the name or alias of the selected volume. |
836 | + |
837 | +Configuring the Journal Path |
838 | +---------------------------- |
839 | + |
840 | +The :ref:`Journal` consists of a series of sequentially numbered files located in directory specified by the configuration parameter ``journalpath``. The application can set this property by calling ``com.persistit.Configuration#setJournalPath`` prior to initializing Persistit or through the property:: |
841 | + |
842 | + journalpath=/ssd/data/my_app_journal |
843 | + |
844 | +The value specified can be either a |
845 | + |
846 | +- directory, in which case files named ``persistit_journal.NNNNNNNNNNNN`` will be created, |
847 | +- or a file name, in which case journal files will be created by appending the suffix ``.NNNNNNNNNNNN``. |
848 | + |
849 | +Recommendations for Physical Media |
850 | +---------------------------------- |
851 | + |
852 | +The journal is written by appending records to the end of the highest-numbered file. Read operations occur while copying page images from the journal to their home volume files. While copying, Persistit attempts to perform large sequential read operations from the journal. Read operations also occur at random when Persistit needs to reload the image of a previously evicted page. |
853 | + |
854 | +Because of these characteristics a modern SSD (solid disk drive) is ideally suited for maintaining the journal. If no SSD is available in the server, placing the journal on a different physical disk drive than the volume file(s) can significantly improve performance. |
855 | + |
856 | +Other Configuration Parameters |
857 | +------------------------------ |
858 | + |
859 | +The following additional properties are defined for Persistit. Other properties may also reside in the Properties object or its backing file; Persistit simply ignores any property not listed here. |
860 | + |
861 | + ``journalsize``: (``com.persistit.Configuration#setJournalSize``) |
862 | + Journal file block size. Default is 1,000,000,000 bytes. A new Persistit rolls over to a new journal file when this |
863 | + size is reached. Generally there is no reason to adjust this setting. |
864 | + |
865 | + ``appendonly``: (``com.persistit.Configuration#setAppendOnly``), True or false (default). |
866 | + When true, Persistit’s journal starts up in *append-only* mode in which modified pages are only written to the |
867 | + journal and not copied to their home volumes. As a consequence, all existing journal files are preserved, and new |
868 | + modifications are written only to newly created journal files. The append-only flag can also be enabled or disabled |
869 | + by application code and through the JMX and RMI interfaces. |
870 | + |
871 | + ``rmiport``: (``com.persistit.Configuration#setRmiPort``) |
872 | + Specifies a port number on which Persistit will create a temporary Remote Method Invocation registry. If this |
873 | + property is specified, Persistit creates a registry and registers a ``com.persistit.Management`` server on it. This |
874 | + allows remote access to management facilities within Persistit and permits the Swing-based administrative utility to |
875 | + attach to and manage a Persistit instance running on a headless server. The ``rmihost`` and ``rmiport`` properties |
876 | + are mutually exclusive. |
877 | + |
878 | + ``rmihost``: (``com.persistit.Configuration#setRmiHost``) |
879 | + Specifies the URL of an Remote Method Invocation registry. If present, Persistit registers its a server for its |
880 | + ``com.persistit.Management`` interface at the specified external registry. The ``rmihost`` and ``rmiport`` |
881 | + properties are mutually exclusive. |
882 | + |
883 | + ``jmx``: (``com.persistit.Configuration#setJmxEnabled``), True or false (default). |
884 | + Specifies whether Persistit registers MXBeans with the platform MBean server. Set this value to ``true`` to enable |
885 | + access from ``jconsole`` and other management tools. |
886 | + |
887 | + ``serialOverride``, ``constructorOverride``: (``com.persistit.Configuration#setSerialOverride`` ``com.persistit.Configuration#setConstructorOverride``) |
888 | + Control aspects of object serialization. See :ref:`Serialization`. |
889 | + |
890 | + ``showgui``: (``com.persistit.Configuration#setShowGUI``), True of False. |
891 | + If true, Persistit attempts to create and display an instance of the AdminUI utility panel within the current JVM. |
892 | + Alternatively, AdminUI uses RMI and can be launched and run remotely if ``rmiport`` or ``rmihost`` has been |
893 | + specified. |
894 | + |
895 | + ``logfile``: (``com.persistit.Configuration#setLogFile``) |
896 | + Name of a log file to which Persistit’s default logger will write diagnostic log entries. Applications generally |
897 | + install a logging adapter to reroute messages through Log4J, SLF4J or other logger. The ``logfile`` property is used |
898 | + only when no adapter has been installed. |
899 | + |
900 | +For all integer-valued properties, the suffix “K” may be used to represent kilo, “M” for mega, “G” for giga and “T” for tera. For example, “2M” represents the value 2,097,152. |
901 | + |
902 | +A Configuration Example |
903 | +----------------------- |
904 | + |
905 | +Following is an example of a Persistit configuration properties file:: |
906 | + |
907 | + datapath = /var/opt/persistit/data |
908 | + logpath = /var/log/persistit |
909 | + logfile = ${logpath}/${timestamp}.log |
910 | + |
911 | + buffer.count.16384 = 5000 |
912 | + |
913 | + volume.1 = ${datapath}/demo_data, create, pageSize:16K, \ |
914 | + initialSize:1M, extensionSize:1M, maximumSize:10G, alias:data |
915 | + |
916 | + volume.2 = ${datapath}/demo_system, create, pageSize:16K, \ |
917 | + initialSize:100K, extensionSize:100K, maximumSize:1G |
918 | + |
919 | + sysvolume = demo_system |
920 | + |
921 | + journalpath = /ssd/persistit_journal |
922 | + |
923 | +With this configuration there will be 5,000 16K buffers in the buffer pool consuming heap space of approximately 93MB including overhead. Persistit will open or create volume files named ``/var/opt/persistit/data/demo_data`` and ``/var/opt/persistit/data/demo_system`` and a journal file named ``/ssd/persistit_journal.0000000000000000``. Persistit will write diagnostic logging output to a file such as ``/var/log/persistit/20110523172213.log``. |
924 | + |
925 | +The ``demo_data`` volume has the alias ``data``. Application code uses the name "data" to refer to it. The ``sysvolume`` property specifies that the ``demo_system`` volume is designated to hold class meta data for serialized objects. |
926 | + |
927 | +Property Value Substitution |
928 | +--------------------------- |
929 | + |
930 | +This example also illustrates how property value substitution can be used within a Persistit configuration. The value of the ``datapath`` replaces ``$\{datapath\}`` in the volume specification. The property name ``datapath`` is arbitrary; you may use any valid property name as a substitution variable. Similarly, the value of ``logpath`` replaces ``$\{logpath\}`` and the pseudo-property ``$\{timestamp\}`` expands to a timestamp in the form ``*yyyyMMddHHmm*`` to provides a unique time-based log file name. |
931 | + |
932 | +Incorporating Java System Properties |
933 | +------------------------------------ |
934 | + |
935 | +You may also specify any configuration property as a Java system property with the prefix ``com.persisit.`` System properties override values specified as properties. For example, you can override the value of ``buffer.count.8192`` specifying:: |
936 | + |
937 | + java -Dcom.persistit.buffer.count.8192=10K -jar MyJar |
938 | + |
939 | +This is also true for substitution property values. For example, ``-Dcom.persistit.logpath=/tmp/`` will place the log files in the ``/tmp`` directory rather than ``/var/log/persistit`` as specified by the configuration file. |
940 | |
941 | === removed file 'doc/Configuration.txt' |
942 | --- doc/Configuration.txt 2012-04-30 22:09:31 +0000 |
943 | +++ doc/Configuration.txt 1970-01-01 00:00:00 +0000 |
944 | @@ -1,246 +0,0 @@ |
945 | -[[Configuration]] |
946 | -= Configuration |
947 | - |
948 | -To initialize Akiban Persistit the embedding application defines a configuration and then invokes one of the +com.persistit.Persistit#initialize+ methods. The configuration defines parameters used to determine locations of files, sizes of buffer pool and journal files, policies and other elements required when Persistit starts up. These parameters are managed by the +com.persistit.Configuration+ class. |
949 | - |
950 | -An application can define the configuration in one of two equivalent ways: |
951 | - |
952 | -- Create a +com.persistit.Configuration+ instance and set its properties through methods such as +com.persistit.Configuration#setJournalPath+. |
953 | -- Specify properties by name in a +java.util.Properties+ instance and then pass the +Properties+ to a +Configuration+ constructor. |
954 | - |
955 | -The following code samples show different ways of using the +com.persistit.Persistit#initialize+ method to configure and start Persistit: |
956 | - |
957 | -[source,java] |
958 | ----- |
959 | -final Persistit db = new Persistit(); |
960 | -final Properties p = new Properties(); |
961 | -p.setProperty("buffer.count.16384", "1000"); |
962 | -p.setProperty("journalpath", "/home/akiban/data/journal"); |
963 | -... |
964 | -db.initialize(p); |
965 | ----- |
966 | - |
967 | -[source,java] |
968 | ----- |
969 | -final Persistit db = new Persistit(); |
970 | -db.initialize("/home/akiban/my_config.properties"); |
971 | ----- |
972 | - |
973 | -[source,java] |
974 | ----- |
975 | -final Persistit db = new Persistit(); |
976 | -final Configuration c = new Configuration(); |
977 | -c.getBufferPoolMap().get(16384).setCount(1000); |
978 | -c.setJournalPath("/home/akiban/data/journal"); |
979 | -... |
980 | -db.initialize(c); |
981 | ----- |
982 | - |
983 | -There are three essential elements in a Persistit configuration: |
984 | - |
985 | -- Memory for the buffer pool(s) |
986 | -- Specifications for +com.persistit.Volume+ instances |
987 | -- Journal file path |
988 | - |
989 | -== Configuring the Buffer Pool |
990 | - |
991 | -During initialization Persistit allocates a fixed amount of heap memory for use as buffers. Depending on the application, it is usually desirable to allocate most of a server’s physical memory to the JVM heap (using the +-Xmx+ and +-Xms+ JVM options) and then to allocate a large fraction of the heap to Persistit buffers. The buffer pool allocation is determined during initialization and remains constant until the embedding application calls +com.persistit.Persistit#close+ to release all resources. |
992 | - |
993 | -The number of buffers, and therefore the heap memory consumed, is determined during initialization by the available heap memory and configuration parameters. The heap memory size is obtained from the platform MemoryMXBean which in turn supplies the value given by the +-Xmx+ JVM property. Configuration parameters are specified by a collection of five +com.persistit.Configuration.BufferPoolConfiguration+ objects, one for each of the possible buffer sizes 1,024, 2,048, 4,096, 8,192 and 16,384 bytes. The method +com.persistit.Configuration#getBufferPoolMap(int)+ gets the +BufferPoolConfiguration+ for a specified buffer size. |
994 | - |
995 | -A +BufferPoolConfiguration+ contains the following attributes: |
996 | - |
997 | -[horizontal] |
998 | -minimumCount:: lower bound on the number of buffers. (Default is zero.) |
999 | -maximumCount:: upper bound on the number of buffers. (Default is zero.) |
1000 | -minimumMemory:: lower bound on memory to allocate. (Default is zero bytes.) |
1001 | -maximumMemory:: upper bound on memory to allocate. (Default is Long.MAX_VALUE bytes.) |
1002 | -reservedMemory:: minimum number of bytes to reserve for use other than buffers. (Default is zero.) |
1003 | -fraction:: floating point value between 0.0f and 1.0f indicating how much of available memory too allocate. (Default is 1.0f.) |
1004 | - |
1005 | -Persistit uses the following algorithm to determine the number of buffers to allocate for each buffer size: |
1006 | - |
1007 | -[source,java] |
1008 | ----- |
1009 | -memoryToUse = fraction * (maxHeap - reservedMemory) |
1010 | -memoryToUse = min(memoryToUse, maximumMemory) |
1011 | -bufferCount = memoryToUse / bufferSizeWithOverhead |
1012 | -bufferCount = max(minimumCount, min(maximumCount, count)) |
1013 | -if (bufferCount * bufferSize > maximumMemory) then FAIL |
1014 | -if ((bufferCount + 1) * bufferSize < minimumMemory) then FAIL |
1015 | -allocate bufferCount buffers |
1016 | ----- |
1017 | - |
1018 | -In other words, Persistit computes a buffer count based on the memory parameters, bounds it by +minimumCount+ and +maximumCount+ and then checks whether the resulting allocation fits within the memory constraints. Note that +bufferSizeWithOverhead+ is about 14% larger than the buffer size; the additional memory is reserved for indexing data and other overhead associated with the buffer. |
1019 | - |
1020 | -Typically an application uses a single buffer size, specifying either an absolute count or memory-based constraints for that size. This can be done by setting the attributes of the appropriate +BufferPoolConfiguration+ object directly, or using Property values. |
1021 | - |
1022 | -The property named +buffer.count._SSSS_+ where _SSSS_ is “1024”, “2048”, “4096”, “8192” or “16384” specifies an absolute count. For example, |
1023 | - |
1024 | ----- |
1025 | -buffer.count.8192 = 10000 |
1026 | ----- |
1027 | - |
1028 | -causes Persistit to allocate 10,000 buffers of size 8192. |
1029 | - |
1030 | -The property +buffer.memory._SSSS_+ specifies memory constraints as shown in this example |
1031 | - |
1032 | ----- |
1033 | -buffer.memory.8192 = 512K,20M,4M,0.6 |
1034 | ----- |
1035 | - |
1036 | -where 512K, 20M, 4M and 0.6 are the +minimumMemory+, +maximumMemory+, +reservedMemory+ and +fraction+, respectively. |
1037 | - |
1038 | -The MemoryMXBean supplies as its maximum heap size value the size given by the +-Xmx+ JVM parameter. |
1039 | - |
1040 | -=== Heap Tuning |
1041 | - |
1042 | -This section pertains to the Oracle HotSpot(tm) Java virtual machine. |
1043 | - |
1044 | -**** |
1045 | -Buffer instances are long-lived objects. To avoid severe garbage collector overhead it is important for all of them to fit in the heap’s tenured generation. This issue becomes especially significant with multi-gigabyte heaps. |
1046 | -**** |
1047 | - |
1048 | -By default the HotSpot server JVM allocates 1/3 of the heap to the new generation and 2/3 to the tenured generation, meaning that allocating more than 2/3 of the heap to buffers will result in bad performance. |
1049 | - |
1050 | -You can increase the fraction by specifying +-XX:NewRatio=_N_+ where _N_ indicates the ratio of tenured generation space to new generation space, or by using the +-Xmn+ parameter to specify an absolute amount of memory for the new generation. Also, setting +-Xms+ equal to +-Xmx+ will avoid numerous garbage collection cycles during the start-up process. |
1051 | - |
1052 | -See [http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html] for further information on tuning the heap and garbage collector for the HotSpot JVM. |
1053 | - |
1054 | -=== Multiple Buffer Pools |
1055 | - |
1056 | -In some cases it may be desirable to allocate two or more buffer pools having buffers of different sizes. For example, it may be beneficial to use a large number of small buffers to hold secondary index pages. |
1057 | - |
1058 | -When specifying multiple memory constraints for multiple buffer pools, the +fraction+ property applies to the available memory before any buffers are allocated. So, for example, |
1059 | - |
1060 | - |
1061 | ----- |
1062 | -buffer.memory.2048=64M,512G,2G,.2 |
1063 | -buffer.memory.16384=64M,512G,2G,.5 |
1064 | ----- |
1065 | - |
1066 | -results in two buffer pools having buffers of size 2,048 bytes and 16,384 bytes, respectively. Assuming that the +-Xmx+ value is 12G, then 2,048 byte buffers will be allocated to fill 20% of 10GByte, 16,384 byte buffers will be allocated to fill 50% of 10GByte, and approximately 5GByte (30% of 10GByte plus 2GByte reserved) will be available to application code. |
1067 | - |
1068 | -== Configuring Volumes |
1069 | - |
1070 | -Persistit creates and/or opens a set of database volume files during start-up. An application can create, open and close additional volumes, but it is often convenient for volumes to be defined in the confiuration, outside of application code. |
1071 | - |
1072 | -The +com.persistit.Configuration#getVolumeList+ method returns a List of +com.persistit.VolumeSpecification+ objects. An application can construct and add new +VolumeSpecification+ instances to this list before calling +com.persistit.Persistit#initialize(Configuration)+. Alternatively, the application can define volume specifications as property values using the syntax: |
1073 | - |
1074 | -+volume._N_ = _path_[,_attrname_[:_attrvalue_]]...+ |
1075 | - |
1076 | -where _N_ is an arbitrary integer, _path_ is the path specification of the volume file, and _attrnames_ include: |
1077 | - |
1078 | -- +pageSize+: Fixed length unit representing one page. Value must be one of 1024, 2048, 4096, 8192 or 16384. To open and use the Volume, the buffer pool must have available buffers of the same size. |
1079 | - |
1080 | -- +create+: Persistit attempts to open an existing volume file with the specified _path_, or create a new one if the file does not exist. |
1081 | - |
1082 | -- +createOnly+: Persistit throw a VolumeAlreadyExistsException if the file specified by path already exists. Otherwise it creates a new file with the specified path. |
1083 | - |
1084 | -- +readOnly+: Opens a volume in read-only mode. An attempt to modify the volume results in a ReadOnlyVolumeException. |
1085 | - |
1086 | -- +initialPages+ or +initialSize+: Specifies the initial size of the newly created volume file, either as the count of pages or as the size in bytes. |
1087 | - |
1088 | -- +extensionPages+ or +extensionSize+: Specifies the extension size of the newly created volume, either as the count of pages or as the size in bytes. This is the size by which the volume file will expand when the volume needs to be enlarged. |
1089 | - |
1090 | -- +maximumPages+ or +maximumSize+: An upper limit on the number of pages this Volume may hold, either as the count of pages or as the size in bytes. An attempt to further enlarge the Volume will generate a VolumeFullException. |
1091 | - |
1092 | -- +alias+: The name of this Volume used in constructing +Exchange+ instances. If unspecified, the name is the simple file name given in the _path_, not including its dotted suffix. |
1093 | - |
1094 | -For example: |
1095 | - |
1096 | ----- |
1097 | -volume.1=/home/akiban/ffdemo,create,pageSize:16K,\ |
1098 | - initialSize:10M,extensionSize:10M,maximumSize:1G |
1099 | ----- |
1100 | - |
1101 | -specifies a volume having the name “ffdemo” in the /home/akiban directory. A new volume will be created if there is no existing volume file, and when created it will have the initial, extension and maximum sizes of 10MByte, 10MByte and 1GByte, respectively. Its page size will be 16KByte, meaning that the configuration must also have a buffer pool of 16KByte buffers. |
1102 | - |
1103 | -=== System Volume |
1104 | - |
1105 | -One volume in a Persistit configuration must be designated as the system volume. It contains class meta data for objects stored serialized in Persistit Values. When a configuration specifies only one volume, that volume implicitly becomes the system volume by default. However, when a configuration specifies multiple volumes, you must indicate which volume will serve as the system volume. There are two ways to do this. By default, Persistit looks for a unique volume named “_system”. You can simply create a volume whose file name is “_system”. |
1106 | - |
1107 | -Alternatively, you can specify a system volume name explicitly with the +sysvolume+ property (or +com.persistit.Configuration#setSysVolume+). The value is the name or alias of the selected volume. |
1108 | - |
1109 | -== Configuring the Journal Path |
1110 | - |
1111 | -The <<Journal>> consists of a series of sequentially numbered files located in directory specified by the configuration parameter +journalpath+. The application can set this property by calling +com.persistit.Configuration#setJournalPath+ prior to initializing Persistit or through the property |
1112 | - |
1113 | ----- |
1114 | -journalpath=/ssd/data/my_app_journal |
1115 | ----- |
1116 | - |
1117 | -The value specified can be either a |
1118 | - |
1119 | -- directory, in which case files named +persistit_journal._NNNNNNNNNNNN_+ will be created, |
1120 | - |
1121 | -- or a file name, in which case journal files will be created by appending the suffix +._NNNNNNNNNNNN_+. |
1122 | - |
1123 | -=== Recommendations for Physical Media |
1124 | - |
1125 | -The journal is written by appending records to the end of the highest-numbered file. Read operations occur while copying page images from the journal to their home volume files. While copying, Persistit attempts to perform large sequential read operations from the journal. Read operations also occur at random when Persistit needs to reload the image of a previously evicted page. |
1126 | - |
1127 | -Because of these characteristics a modern SSD (solid disk drive) is ideally suited for maintaining the journal. If no SSD is available in the server, placing the journal on a different physical disk drive than the volume file(s) can significantly improve performance. |
1128 | - |
1129 | -== Other Configuration Parameters |
1130 | - |
1131 | -The following additional properties are defined for Persistit. Other properties may also reside in the Properties object or its backing file; Persistit simply ignores any property not listed here. |
1132 | - |
1133 | -[horizontal] |
1134 | -+journalsize+:: (+com.persistit.Configuration#setJournalSize+) Journal file block size. Default is 1,000,000,000 bytes. A new Persistit rolls over to a new journal file when this size is reached. Generally there is no reason to adjust this setting. |
1135 | - |
1136 | -+appendonly+:: (+com.persistit.Configuration#setAppendOnly+) True or false (default). When true, Persistit’s journal starts up in _append-only_ mode in which modified pages are only written to the journal and not copied to their home volumes. As a consequence, all existing journal files are preserved, and new modifications are written only to newly created journal files. The append-only flag can also be enabled or disabled by application code and through the JMX and RMI interfaces. |
1137 | - |
1138 | -+rmiport+:: (+com.persistit.Configuration#setRmiPort+) Specifies a port number on which Persistit will create a temporary Remote Method Invocation registry. If this property is specified, Persistit creates a registry and registers a +com.persistit.Management+ server on it. This allows remote access to management facilities within Persistit and permits the Swing-based administrative utility to attach to and manage a Persistit instance running on a headless server. The +rmihost+ and +rmiport+ properties are mutually exclusive. |
1139 | - |
1140 | -+rmihost+:: (+com.persistit.Configuration#setRmiHost+) Specifies the URL of an Remote Method Invocation registry. If present, Persistit registers its a server for its +com.persistit.Management+ interface at the specified external registry. The +rmihost+ and +rmiport+ properties are mutually exclusive. |
1141 | - |
1142 | -+jmx+:: (+com.persistit.Configuration#setJmxEnabled+) True or false (default). Specifies whether Persistit registers MXBeans with the platform MBean server. Set this value to +true+ to enable access from +jconsole+ and other management tools. |
1143 | - |
1144 | -+serialOverride+, +constructorOverride+:: (+com.persistit.Configuration#setSerialOverride+ +com.persistit.Configuration#setConstructorOverride+) Control aspects of object serialization. See <<Serialization>>. |
1145 | - |
1146 | -+showgui+:: ((+com.persistit.Configuration#setShowGUI+) True of False. If true, Persistit attempts to create and display an instance of the AdminUI utility panel within the current JVM. (Alternatively, AdminUI uses RMI and can be launched and run remotely if +rmiport+ or +rmihost+ has been specified. |
1147 | - |
1148 | -+logfile+:: (+com.persistit.Configuration#setLogFile+) Name of a log file to which Persistit’s default logger will write diagnostic log entries. Applications generally install a logging adapter to reroute messages through Log4J, SLF4J or other logger. The +logfile+ property is used only when no adapter has been installed. |
1149 | - |
1150 | -For all integer-valued properties, the suffix “K” may be used to represent kilo, “M” for mega, “G” for giga and “T” for tera. For example, “2M” represents the value 2,097,152. |
1151 | - |
1152 | -== A Configuration Example |
1153 | - |
1154 | -Following is an example of a Persistit configuration properties file: |
1155 | - |
1156 | ----- |
1157 | -datapath = /var/opt/persistit/data |
1158 | -logpath = /var/log/persistit |
1159 | -logfile = ${logpath}/${timestamp}.log |
1160 | - |
1161 | -buffer.count.16384 = 5000 |
1162 | - |
1163 | -volume.1 = ${datapath}/demo_data, create, pageSize:16K, \ |
1164 | - initialSize:1M, extensionSize:1M, maximumSize:10G, alias:data |
1165 | - |
1166 | -volume.2 = ${datapath}/demo_system, create, pageSize:16K, \ |
1167 | - initialSize:100K, extensionSize:100K, maximumSize:1G |
1168 | - |
1169 | -sysvolume = demo_system |
1170 | - |
1171 | -journalpath = /ssd/persistit_journal |
1172 | ----- |
1173 | - |
1174 | -With this configuration there will be 5,000 16K buffers in the buffer pool consuming heap space of approximately 93MB including overhead. Persistit will open or create volume files named +/var/opt/persistit/data/demo_data+ and +/var/opt/persistit/data/demo_system+ and a journal file named +/ssd/persistit_journal.0000000000000000+. Persistit will write diagnostic logging output to a file such as +/var/log/persistit/20110523172213.log+. |
1175 | - |
1176 | -The +demo_data+ volume has the alias +data+. Application code uses the name "data" to refer to it. The +sysvolume+ property specifies that the +demo_system+ volume is designated to hold class meta data for serialized objects. |
1177 | - |
1178 | -=== Property Value Substitution |
1179 | - |
1180 | -This example also illustrates how property value substitution can be used within a Persistit configuration. The value of the +datapath+ replaces +$\{datapath\}+ in the volume specification. The property name +datapath+ is arbitrary; you may use any valid property name as a substitution variable. Similarly, the value of +logpath+ replaces +$\{logpath\}+ and the pseudo-property +$\{timestamp\}+ expands to a timestamp in the form +_yyyyMMddHHmm_+ to provides a unique time-based log file name. |
1181 | - |
1182 | -=== Incorporating Java System Properties |
1183 | - |
1184 | -You may also specify any configuration property as a Java system property with the prefix +com.persisit.+ System properties override values specified as properties. For example, you can override the value of +buffer.count.8192+ specifying |
1185 | - |
1186 | ----- |
1187 | -java -Dcom.persistit.buffer.count.8192=10K -jar MyJar |
1188 | ----- |
1189 | - |
1190 | -This is also true for substitution property values. For example, +-Dcom.persistit.logpath=/tmp/+ will place the log files in the +/tmp+ directory rather than +/var/log/persistit+ as specified by the configuration file. |
1191 | |
1192 | === added file 'doc/GettingStarted.rst' |
1193 | --- doc/GettingStarted.rst 1970-01-01 00:00:00 +0000 |
1194 | +++ doc/GettingStarted.rst 2012-05-30 18:23:19 +0000 |
1195 | @@ -0,0 +1,270 @@ |
1196 | + |
1197 | +Getting Started with Akiban Persistit |
1198 | +===================================== |
1199 | + |
1200 | +Welcome! |
1201 | + |
1202 | +We have worked hard to make Akiban Persistit(TM) exceptionally fast, reliable, simple and lightweight. We hope you will enjoy learning more about it and using it. |
1203 | + |
1204 | +Akiban Persistit is a key/value data storage library written in Java(TM). Key features include: |
1205 | + |
1206 | +- support for highly concurrent transaction processing with multi-version concurrency control |
1207 | +- optimized serialization and deserialization mechanism for Java primitives and objects |
1208 | +- multi-segment (compound) keys to enable a natural logical key hierarchy |
1209 | +- support for long records (megabytes) |
1210 | +- implementation of a persistent SortedMap |
1211 | +- extensive management capability including command-line and GUI tools |
1212 | + |
1213 | +This chapter briefly and informally introduces and demonstrates various Persistit features through examples. Subsequent chapters and the Javadoc API documentation provides a detailed reference guide to the product. |
1214 | + |
1215 | +Download and Install |
1216 | +-------------------- |
1217 | + |
1218 | +Download ``akiban-persistit-3.xx.yy.zip`` from http://www.akiban.com/persistit/download.html. |
1219 | + |
1220 | +Unpack the distribution kit into a convenient directory using any unzip utility. For example, use ``jar`` to unpack the distribution kit to the current working directory as follows: |
1221 | +.. code-block:: |
1222 | + |
1223 | + jar xvzf akiban-persistit-core-3.xx.yy.zip |
1224 | + |
1225 | +Review the ``LICENSE.html`` and ``README.html`` files located in the root of the installation directory. Persistit is licensed under the GNU Affero General Public License. By installing, copying or otherwise using the Software contained in the distribution kit, you agree to be bound by the terms of the license agreement. If you do not agree to these terms, remove and destroy all copies of the software in your possession immediately. |
1226 | + |
1227 | +Working with Persistit |
1228 | +---------------------- |
1229 | + |
1230 | +Add the ``akiban-persistit-core-3.xx.yy.jar`` from the ``lib`` directory of the distribution kit to your project's classpath. For example, copy it to ``jre/lib/ext`` in your Java Runtime Environment, or add it to your classpath environment variable. |
1231 | + |
1232 | +That's it. You are ready to work with Persistit. |
1233 | + |
1234 | +Examples |
1235 | +^^^^^^^^ |
1236 | + |
1237 | +Review the ``examples`` directory. Here you will find functional examples of varying complexity. |
1238 | + |
1239 | + ``examples/HelloWorld`` |
1240 | + source code for the example illustrating this chapter |
1241 | + ``examples/SimpleDemo`` |
1242 | + short, simple program similar to HelloWorld |
1243 | + ``examples/SimpleBench`` |
1244 | + a small micro-benchmark measuring the speed of insert, traversal, random updates, etc. |
1245 | + ``examples/SimpleTransaction`` |
1246 | + example demonstrating use of Persisit’s multi-version currency control (MVCC) transactions |
1247 | + ``examples/FindFile`` |
1248 | + a somewhat larger example that uses Persistit as the backing store for file finder utility |
1249 | + ``example/PersistitMapDemo`` |
1250 | + demonstration of the PersistitMap interface |
1251 | + |
1252 | +HelloWorld |
1253 | +---------- |
1254 | + |
1255 | +Before going further let's honor tradition with a small program that stores, fetches and displays the phrase “Hello World.” In this program we will create a record with the key “Hello” and the value “World”. |
1256 | + |
1257 | +.. HelloWorld.java |
1258 | + |
1259 | +.. code-block:: java |
1260 | + |
1261 | + import com.persistit.Exchange; |
1262 | + import com.persistit.Key; |
1263 | + import com.persistit.Persistit; |
1264 | + |
1265 | + public class HelloWorld { |
1266 | + public static void main(String[] args) throws Exception { |
1267 | + Persistit db = new Persistit(); |
1268 | + try { |
1269 | + // Read configuration from persistit.properties, allocate |
1270 | + // buffers, open Volume, and perform recovery processing |
1271 | + // if necessary. |
1272 | + // |
1273 | + db.initialize(); |
1274 | + // |
1275 | + // Create an Exchange, which is a thread-private facade for |
1276 | + // accessing data in a Persistit Tree. This Exchange will |
1277 | + // access a Tree called "greetings" in a Volume called |
1278 | + // "hwdemo". It will create a new Tree by that name |
1279 | + // if one does not already exist. |
1280 | + // |
1281 | + Exchange dbex = db.getExchange("hwdemo", "greetings", true); |
1282 | + // |
1283 | + // Set up the Value field of the Exchange. |
1284 | + // |
1285 | + dbex.getValue().put("World"); |
1286 | + // |
1287 | + // Set up the Key field of the Exchange. |
1288 | + // |
1289 | + dbex.getKey().append("Hello"); |
1290 | + // |
1291 | + // Ask Persistit to put this key/value pair into the Tree. |
1292 | + // Until this point, the changes to the Exchange are local |
1293 | + // to this thread. |
1294 | + // |
1295 | + dbex.store(); |
1296 | + // |
1297 | + // Prepare to traverse all the keys in the Tree (of which there |
1298 | + // is currently only one!) and for each key display its value. |
1299 | + // |
1300 | + dbex.getKey().to(Key.BEFORE); |
1301 | + while (dbex.next()) { |
1302 | + System.out.println(dbex.getKey().indexTo(0).decode() + " " |
1303 | + + dbex.getValue().get()); |
1304 | + } |
1305 | + db.releaseExchange(dbex); |
1306 | + } finally { |
1307 | + // Always close Persistit. If the application does not do |
1308 | + // this, Persistit's background threads will keep the JVM from |
1309 | + // terminating. |
1310 | + // |
1311 | + db.close(); |
1312 | + } |
1313 | + } |
1314 | + } |
1315 | + |
1316 | +Concepts |
1317 | +-------- |
1318 | + |
1319 | +Although ``HelloWorld.java`` is not very useful, it demonstrates several of the basic building blocks of the Persistit API. |
1320 | + |
1321 | +Initialization and Configuration |
1322 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
1323 | + |
1324 | +Before accessing any data, ``HelloWorld.java`` calls one of the ``com.persistit.Persistit#initialize`` methods of ``com.persistit.Persistit``. This sets up the memory configuration for buffers and the path names of Persistit volume and journal files. Alternative versions of the initialize method accept configuration information from a ``java.util.Properties`` object, from a specified properties file, or by default from the file named ``persistit.properties``. |
1325 | + |
1326 | +In this example, ``persistit.properties`` looks like this:: |
1327 | + |
1328 | + datapath=. |
1329 | + buffer.count.8192=32 |
1330 | + volume.1=${datapath}/hwdemo,create,pageSize:8192,\ |
1331 | + initialPages:5,extensionPages:5,maximumPages:100000 |
1332 | + journalpath=${datapath}/hwdemo_journal |
1333 | + |
1334 | +See :ref:`Configuration` for additional information about Persistit configuration properties. |
1335 | + |
1336 | +Volumes and Trees |
1337 | +^^^^^^^^^^^^^^^^^ |
1338 | + |
1339 | +A configuration defines one or more volume files that will contain stored Persistit data. Usually you will specify the ``create`` flag, which allows Persistit to create a new volume if the file does not already exist. Creating a new file also establishes the initial size and growth parameters for that volume. |
1340 | + |
1341 | +Each volume may contain an unlimited number of named trees. Each tree within a volume embodies a logically distinct B-Tree index structure. Think of a tree as simply a named key space within a volume. |
1342 | + |
1343 | +``HelloWorld.java`` stores its key/value pair in a tree called “greetings” in a volume named “hwdemo”. This is specified by constructing an Exchange. |
1344 | + |
1345 | +Exchanges |
1346 | +--------- |
1347 | + |
1348 | +The ``com.persistit.Exchange`` class is the primary facade for interacting with Persistit data. It is so-named because it allows an application to exchange information with the database. An Exchange provides methods for storing, deleting, fetching and traversing key/value pairs. |
1349 | + |
1350 | +The method |
1351 | + |
1352 | +.. code-block:: java |
1353 | + |
1354 | + Exchange dbex = db.getExchange("hwdemo", "greetings", true); |
1355 | + |
1356 | +in ``HelloWorld.java`` finds a volume named "hwdemo" and attempts to find a tree in it named "greetings". If there is no such tree, ``getExchange`` creates it. |
1357 | + |
1358 | +Methods ``com.persistit.Persistit#getExchange`` and ``com.persistit.Persistit#releaseExchange`` maintain a pool of reusable Exchange objects designed for use by multi-threaded applications such as web applications. If a suitable exchange already exists, ``getExchange`` returns it; otherwise it constructs a new one. |
1359 | + |
1360 | +The Exchange looks up the volume name “hwdemo” by matching it against the volumes specified in the configuration. The match is based on the simple file name of the volume after removing its final dotted suffix. For example, the volume name “hwdemo” matches the volume specification ``${datapath}/hwdemo.v00``. |
1361 | + |
1362 | +Each Exchange is implicitly associated with a ``com.persistit.Key`` and a ``com.persistit.Value``. Typically you work with an Exchange in one of the following patterns: |
1363 | + |
1364 | +- Modify the Key, modify the Value and then perform a ``com.persistit.Exchange#store`` operation. |
1365 | +- Modify the Key, perform a ``com.persistit.Exchange#fetch`` operation and then read the Value. |
1366 | +- Modify the Key and then perform a ``com.persistit.Exchange#remove`` operation. |
1367 | +- Optionally modify the Key, perform a ``com.persistit.Exchange#next``, ``com.persistit.Exchange#previous`` or ``com.persistit.Exchange#traverse`` operation, then read the resulting Key and/or Value. |
1368 | + |
1369 | +These methods and their variants provide the foundation for using Persistit. |
1370 | + |
1371 | +Records |
1372 | +^^^^^^^ |
1373 | + |
1374 | +In Persistit, a database record consists of a Key and a Value. The terms “record” and “key/value pair” are used interchangeably. |
1375 | + |
1376 | +When you store a record, Persistit searches for a previously stored record having the same key. If there is such a record, Persistit replaces its value. If there is no such record, Persistit inserts a new one. Like a Java Map, Persistit stores at most one value per key, and every record in a Tree has a unique key value. |
1377 | + |
1378 | +Keys |
1379 | +^^^^ |
1380 | + |
1381 | +A Key contains a unique identifier for key/value pair - or record - in a tree. The identifier consists of a sequence of one or more Java values encoded into an array of bytes stored in the volume file. |
1382 | + |
1383 | +Key instances are mutable. Your application typically changes an Exchange's Key in preparation for fetching or retrieving data. In particular, you can append, remove or replace one or more values in a Key. Each value you append is called a *key segment*. You append multiple key segments to implement concatenated keys. See ``com.persistit.Key`` for additional information on constructing keys and the ordering of key traversal within a tree. |
1384 | + |
1385 | +The ``HelloWorld.java`` example appends “Hello” to the Exchange’s Key object in this line: |
1386 | + |
1387 | +.. code-block:: java |
1388 | + |
1389 | + dbex.getKey().append("Hello"); |
1390 | + |
1391 | +The result is a key with a single key segment. |
1392 | + |
1393 | +Values |
1394 | +^^^^^^ |
1395 | + |
1396 | +A Value object represents the serialized state of a Java object or a primitive value. It is a staging area for data being transferred from or to the database by ``fetch``, ``traverse`` and ``store`` operations. |
1397 | + |
1398 | +Value instances are mutable. The ``fetch`` and ``traverse`` operations modify the state of an Exchange's Value instance to represent the value associated with some Key. Your application executes methods to modify the state of the Value instance in preparation for storing new data values into the database. |
1399 | + |
1400 | +Numerous methods allow you to serialize and deserialize primitives values and objects into and from a Value object. For example, in ``HelloWorld.java``, the statement |
1401 | + |
1402 | +.. code-block:: java |
1403 | + |
1404 | + dbex.getValue().put("World"); |
1405 | + |
1406 | +serializes the string “World” into the backing byte array of the Exchange’s Value object and |
1407 | + |
1408 | +.. code-block:: java |
1409 | + |
1410 | + System.out.println( |
1411 | + dbex.getKey().indexTo(0).decode() + " " + |
1412 | + dbex.getValue().get()); |
1413 | + |
1414 | +deserializes and prints an object value from the Key and another object value from the Value. Value also has methods such as ``getInt``, ``getLong``, ``getByteArray`` to decode primitive and array values directly. |
1415 | + |
1416 | +Storing and Fetching Data |
1417 | +^^^^^^^^^^^^^^^^^^^^^^^^^ |
1418 | + |
1419 | +Finally, it is these two methods in ``HelloWorld.java`` that cause the Exchange object to share data with the B-Tree, making it persistent and potentially available to other threads: |
1420 | + |
1421 | +.. code-block:: java |
1422 | + |
1423 | + dbex.store(); |
1424 | + ... |
1425 | + while (dbex.next()) { ... } |
1426 | + |
1427 | +Closing Persistit |
1428 | +^^^^^^^^^^^^^^^^^ |
1429 | + |
1430 | +Persistit creates one or more background threads that lazily write data to the Volume files and perform other maintenance activities. Be sure to invoke the ``com.persistit.Persistit#close`` method to allow these threads to finish their work and exit properly. The pattern illustrated in ``HelloWorld.java``, using a *try/finally* block to invoke ``close``, is strongly recommended. |
1431 | + |
1432 | +The ``com.persistit.Persistit#close(boolean)`` method optionally flushes all data to disk from the buffer pool before shutting down. Specifying the ``false`` option will close Persistit more quickly will lose recent updates if they were not performed inside of transactions, or will potentially require a longer recovery process during the next startup to reapply committed transactions. |
1433 | +Additional Topics |
1434 | +----------------- |
1435 | + |
1436 | +PersistitMap |
1437 | +^^^^^^^^^^^^ |
1438 | +A particularly easy way to get started with Persistit is to use its built-in ``com.persistit.PersistitMap`` implementation. PersistitMap implements the ``java.util.SortedMap`` interface, so it can directly replace ``java.util.TreeMap`` or other kinds of Map in existing Java code. |
1439 | + |
1440 | +See :ref:`PersistitMap`. |
1441 | + |
1442 | +KeyFilters |
1443 | +^^^^^^^^^^ |
1444 | + |
1445 | +A ``com.persistit.KeyFilter`` can be supplied to restrict the results traversal operation in a convenient and |
1446 | + |
1447 | +Transactions |
1448 | +^^^^^^^^^^^^ |
1449 | + |
1450 | +Persistit provides ACID Transaction support with multi-version concurrency control (MCC) and adjustable durability policy. |
1451 | + |
1452 | +See :ref:`Transactions`. |
1453 | + |
1454 | +Managing Persistit |
1455 | +^^^^^^^^^^^^^^^^^^ |
1456 | + |
1457 | +Persistit provides several mechanisms for managing Persistit operation within an application. These include |
1458 | + |
1459 | +- JMX MXBeans |
1460 | +- The ``com.persistit.Management`` object which provides programmatic access to many management operations |
1461 | +- The ``com.persistit.CLI`` object which provides a command-line interface for various management operations |
1462 | +- The AdminUI tool which provides a graphical client interface for examining records and other resources |
1463 | +- Logging interface design for easy embedding in host applications |
1464 | + |
1465 | +See :ref:`Management`. |
1466 | |
1467 | === removed file 'doc/GettingStarted.txt' |
1468 | --- doc/GettingStarted.txt 2012-04-24 02:37:12 +0000 |
1469 | +++ doc/GettingStarted.txt 1970-01-01 00:00:00 +0000 |
1470 | @@ -1,255 +0,0 @@ |
1471 | - |
1472 | -= Getting Started with Akiban Persistit |
1473 | - |
1474 | - |
1475 | -Welcome! |
1476 | - |
1477 | -We have worked hard to make Akiban Persistit(TM) exceptionally fast, reliable, simple and lightweight. We hope you will enjoy learning more about it and using it. |
1478 | - |
1479 | -Akiban Persistit is a key/value data storage library written in Java(TM). Key features include: |
1480 | - |
1481 | -- support for highly concurrent transaction processing with multi-version concurrency control |
1482 | -- optimized serialization and deserialization mechanism for Java primitives and objects |
1483 | -- multi-segment (compound) keys to enable a natural logical key hierarchy |
1484 | -- support for long records (megabytes) |
1485 | -- implementation of a persistent SortedMap |
1486 | -- extensive management capability including command-line and GUI tools |
1487 | - |
1488 | -This chapter briefly and informally introduces and demonstrates various Persistit features through examples. Subsequent chapters and the Javadoc API documentation provides a detailed reference guide to the product. |
1489 | - |
1490 | -== Download and Install |
1491 | - |
1492 | -Download +akiban-persistit-3.xx.yy.zip+ from http://www.akiban.com/persistit/download.html. |
1493 | - |
1494 | -Unpack the distribution kit into a convenient directory using any unzip utility. For example, use +jar+ to unpack the distribution kit to the current working directory as follows: |
1495 | ----- |
1496 | -jar xvzf akiban-persistit-core-3.xx.yy.zip |
1497 | ----- |
1498 | - |
1499 | -Review the +LICENSE.html+ and +README.html+ files located in the root of the installation directory. Persistit is licensed under the XXXXXX XXXXXXX License. By installing, copying or otherwise using the Software contained in the distribution kit, you agree to be bound by the terms of the license agreement. If you do not agree to these terms, remove and destroy all copies of the software in your possession immediately. |
1500 | - |
1501 | -== Working with Persistit |
1502 | - |
1503 | -Add the +akiban-persistit-core-3.xx.yy.jar+ from the +lib+ directory of the distribution kit to your project's classpath. For example, copy it to +jre/lib/ext+ in your Java Runtime Environment, or add it to your classpath environment variable. |
1504 | - |
1505 | -That's it. You are ready to work with Persistit. |
1506 | - |
1507 | -=== Examples |
1508 | - |
1509 | -Review the +examples+ directory. Here you will find functional examples of varying complexity. |
1510 | - |
1511 | -[horizontal] |
1512 | -+examples/HelloWorld+:: source code for the example illustrating this chapter |
1513 | -+examples/SimpleDemo+:: short, simple program similar to HelloWorld |
1514 | -+examples/SimpleBench+:: a small micro-benchmark measuring the speed of insert, traversal, random updates, etc. |
1515 | -+examples/SimpleTransaction+:: example demonstrating use of Persisit’s multi-version currency control (MVCC) transactions |
1516 | -+examples/FindFile+:: a somewhat larger example that uses Persistit as the backing store for file finder utility |
1517 | -+example/PersistitMapDemo+:: demonstration of the PersistitMap interface |
1518 | - |
1519 | -== HelloWorld |
1520 | - |
1521 | -Before going further let's honor tradition with a small program that stores, fetches and displays the phrase “Hello World.” In this program we will create a record with the key “Hello” and the value “World”. |
1522 | - |
1523 | -.HelloWorld.java |
1524 | -[source,java] |
1525 | ----- |
1526 | -import com.persistit.Exchange; |
1527 | -import com.persistit.Key; |
1528 | -import com.persistit.Persistit; |
1529 | - |
1530 | -public class HelloWorld { |
1531 | - public static void main(String[] args) throws Exception { |
1532 | - Persistit db = new Persistit(); |
1533 | - try { |
1534 | - // Read configuration from persistit.properties, allocate |
1535 | - // buffers, open Volume, and perform recovery processing |
1536 | - // if necessary. |
1537 | - // |
1538 | - db.initialize(); |
1539 | - // |
1540 | - // Create an Exchange, which is a thread-private facade for |
1541 | - // accessing data in a Persistit Tree. This Exchange will |
1542 | - // access a Tree called "greetings" in a Volume called |
1543 | - // "hwdemo". It will create a new Tree by that name |
1544 | - // if one does not already exist. |
1545 | - // |
1546 | - Exchange dbex = db.getExchange("hwdemo", "greetings", true); |
1547 | - // |
1548 | - // Set up the Value field of the Exchange. |
1549 | - // |
1550 | - dbex.getValue().put("World"); |
1551 | - // |
1552 | - // Set up the Key field of the Exchange. |
1553 | - // |
1554 | - dbex.getKey().append("Hello"); |
1555 | - // |
1556 | - // Ask Persistit to put this key/value pair into the Tree. |
1557 | - // Until this point, the changes to the Exchange are local |
1558 | - // to this thread. |
1559 | - // |
1560 | - dbex.store(); |
1561 | - // |
1562 | - // Prepare to traverse all the keys in the Tree (of which there |
1563 | - // is currently only one!) and for each key display its value. |
1564 | - // |
1565 | - dbex.getKey().to(Key.BEFORE); |
1566 | - while (dbex.next()) { |
1567 | - System.out.println(dbex.getKey().indexTo(0).decode() + " " |
1568 | - + dbex.getValue().get()); |
1569 | - } |
1570 | - db.releaseExchange(dbex); |
1571 | - } finally { |
1572 | - // Always close Persistit. If the application does not do |
1573 | - // this, Persistit's background threads will keep the JVM from |
1574 | - // terminating. |
1575 | - // |
1576 | - db.close(); |
1577 | - } |
1578 | - } |
1579 | -} |
1580 | ----- |
1581 | - |
1582 | -== Concepts |
1583 | - |
1584 | -Although +HelloWorld.java+ is not very useful, it demonstrates several of the basic building blocks of the Persistit API. |
1585 | - |
1586 | -=== Initialization and Configuration |
1587 | - |
1588 | -Before accessing any data, +HelloWorld.java+ calls one of the +com.persistit.Persistit#initialize+ methods of +com.persistit.Persistit+. This sets up the memory configuration for buffers and the path names of Persistit volume and journal files. Alternative versions of the initialize method accept configuration information from a +java.util.Properties+ object, from a specified properties file, or by default from the file named +persistit.properties+. |
1589 | - |
1590 | -In this example, +persistit.properties+ looks like this: |
1591 | - |
1592 | ----- |
1593 | -datapath=. |
1594 | -buffer.count.8192=32 |
1595 | -volume.1=${datapath}/hwdemo,create,pageSize:8192,\ |
1596 | - initialPages:5,extensionPages:5,maximumPages:100000 |
1597 | -journalpath=${datapath}/hwdemo_journal |
1598 | ----- |
1599 | - |
1600 | -See <<Configuration>> for additional information about Persistit configuration properties. |
1601 | - |
1602 | -=== Volumes and Trees |
1603 | - |
1604 | -A configuration defines one or more volume files that will contain stored Persistit data. Usually you will specify the +create+ flag, which allows Persistit to create a new volume if the file does not already exist. Creating a new file also establishes the initial size and growth parameters for that volume. |
1605 | - |
1606 | -Each volume may contain an unlimited number of named trees. Each tree within a volume embodies a logically distinct B-Tree index structure. Think of a tree as simply a named key space within a volume. |
1607 | - |
1608 | -+HelloWorld.java+ stores its key/value pair in a tree called “greetings” in a volume named “hwdemo”. This is specified by constructing an Exchange. |
1609 | - |
1610 | -=== Exchanges |
1611 | - |
1612 | -The +com.persistit.Exchange+ class is the primary facade for interacting with Persistit data. It is so-named because it allows an application to exchange information with the database. An Exchange provides methods for storing, deleting, fetching and traversing key/value pairs. |
1613 | - |
1614 | -The method |
1615 | - |
1616 | -[source,java] |
1617 | ----- |
1618 | -Exchange dbex = db.getExchange("hwdemo", "greetings", true); |
1619 | ----- |
1620 | - |
1621 | -in +HelloWorld.java+ finds a volume named "hwdemo" and attempts to find a tree in it named "greetings". If there is no such tree, +getExchange+ creates it. |
1622 | - |
1623 | -Methods +com.persistit.Persistit#getExchange+ and +com.persistit.Persistit#releaseExchange+ maintain a pool of reusable Exchange objects designed for use by multi-threaded applications such as web applications. If a suitable exchange already exists, +getExchange+ returns it; otherwise it constructs a new one. |
1624 | - |
1625 | -The Exchange looks up the volume name “hwdemo” by matching it against the volumes specified in the configuration. The match is based on the simple file name of the volume after removing its final dotted suffix. For example, the volume name “hwdemo” matches the volume specification +${datapath}/hwdemo.v00+. |
1626 | - |
1627 | -Each Exchange is implicitly associated with a +com.persistit.Key+ and a +com.persistit.Value+. Typically you work with an Exchange in one of the following patterns: |
1628 | - |
1629 | -- Modify the Key, modify the Value and then perform a +com.persistit.Exchange#store+ operation. |
1630 | -- Modify the Key, perform a +com.persistit.Exchange#fetch+ operation and then read the Value. |
1631 | -- Modify the Key and then perform a +com.persistit.Exchange#remove+ operation. |
1632 | -- Optionally modify the Key, perform a +com.persistit.Exchange#next+, +com.persistit.Exchange#previous+ or +com.persistit.Exchange#traverse+ operation, then read the resulting Key and/or Value. |
1633 | - |
1634 | -These methods and their variants provide the foundation for using Persistit. |
1635 | - |
1636 | -=== Records |
1637 | - |
1638 | -In Persistit, a database record consists of a Key and a Value. The terms “record” and “key/value pair” are used interchangeably. |
1639 | - |
1640 | -When you store a record, Persistit searches for a previously stored record having the same key. If there is such a record, Persistit replaces its value. If there is no such record, Persistit inserts a new one. Like a Java Map, Persistit stores at most one value per key, and every record in a Tree has a unique key value. |
1641 | - |
1642 | -=== Keys |
1643 | - |
1644 | -A Key contains a unique identifier for key/value pair - or record - in a tree. The identifier consists of a sequence of one or more Java values encoded into an array of bytes stored in the volume file. |
1645 | - |
1646 | -Key instances are mutable. Your application typically changes an Exchange's Key in preparation for fetching or retrieving data. In particular, you can append, remove or replace one or more values in a Key. Each value you append is called a _key segment_. You append multiple key segments to implement concatenated keys. See +com.persistit.Key+ for additional information on constructing keys and the ordering of key traversal within a tree. |
1647 | - |
1648 | -The +HelloWorld.java+ example appends “Hello” to the Exchange’s Key object in this line: |
1649 | - |
1650 | -[source,java] |
1651 | ----- |
1652 | - dbex.getKey().append("Hello"); |
1653 | ----- |
1654 | - |
1655 | -The result is a key with a single key segment. |
1656 | - |
1657 | -=== Values |
1658 | - |
1659 | -A Value object represents the serialized state of a Java object or a primitive value. It is a staging area for data being transferred from or to the database by +fetch+, +traverse+ and +store+ operations. |
1660 | - |
1661 | -Value instances are mutable. The +fetch+ and +traverse+ operations modify the state of an Exchange's Value instance to represent the value associated with some Key. Your application executes methods to modify the state of the Value instance in preparation for storing new data values into the database. |
1662 | - |
1663 | -Numerous methods allow you to serialize and deserialize primitives values and objects into and from a Value object. For example, in +HelloWorld.java+, the statement |
1664 | - |
1665 | -[source,java] |
1666 | ----- |
1667 | - dbex.getValue().put("World"); |
1668 | ----- |
1669 | -serializes the string “World” into the backing byte array of the Exchange’s Value object and |
1670 | - |
1671 | -[source,java] |
1672 | ----- |
1673 | - System.out.println( |
1674 | - dbex.getKey().indexTo(0).decode() + " " + |
1675 | - dbex.getValue().get()); |
1676 | ----- |
1677 | -deserializes and prints an object value from the Key and another object value from the Value. Value also has methods such as +getInt+, +getLong+, +getByteArray+ to decode primitive and array values directly. |
1678 | - |
1679 | -=== Storing and Fetching Data |
1680 | - |
1681 | -Finally, it is these two methods in +HelloWorld.java+ that cause the Exchange object to share data with the B-Tree, making it persistent and potentially available to other threads: |
1682 | - |
1683 | -[source,java] |
1684 | ----- |
1685 | - dbex.store(); |
1686 | - ... |
1687 | - while (dbex.next()) { ... } |
1688 | ----- |
1689 | - |
1690 | -=== Closing Persistit |
1691 | - |
1692 | -Persistit creates one or more background threads that lazily write data to the Volume files and perform other maintenance activities. Be sure to invoke the +com.persistit.Persistit.close+ method to allow these threads to finish their work and exit properly. The pattern illustrated in +HelloWorld.java+, using a _try/finally_ block to invoke +close+, is strongly recommended. |
1693 | - |
1694 | -The +close+ flushes all data from |
1695 | - |
1696 | - |
1697 | -== Additional Topics |
1698 | - |
1699 | -=== PersistitMap |
1700 | - |
1701 | -A particularly easy way to get started with Persistit is to use its built-in +com.persistit.PersistitMap+ implementation. PersistitMap implements the +java.util.SortedMap+ interface, so it can directly replace +java.util.TreeMap+ or other kinds of Map in existing Java code. |
1702 | - |
1703 | -See <<PersistitMap>>. |
1704 | - |
1705 | -=== KeyFilters |
1706 | - |
1707 | -A +com.persistit.KeyFilter+ can be supplied to restrict the results traversal operation in a convenient and |
1708 | - |
1709 | -=== Transactions |
1710 | - |
1711 | -Persistit provides ACID Transaction support with multi-version concurrency control (MCC) and adjustable durability policy. |
1712 | - |
1713 | -See <<Transactions>>. |
1714 | - |
1715 | -=== Managing Persistit |
1716 | - |
1717 | -Persistit provides several mechanisms for managing Persistit operation within an application. These include |
1718 | - |
1719 | -- JMX MXBeans |
1720 | -- The +com.persistit.Management+ object which provides programmatic access to many management operations |
1721 | -- The +com.persistit.CLI+ object which provides a command-line interface for various management operations |
1722 | -- The AdminUI tool which provides a graphical client interface for examining records and other resources |
1723 | -- Logging interface design for easy embedding in host applications |
1724 | - |
1725 | -See <<Management>>. |
1726 | |
1727 | === added file 'doc/Management.rst' |
1728 | --- doc/Management.rst 1970-01-01 00:00:00 +0000 |
1729 | +++ doc/Management.rst 2012-05-30 18:23:19 +0000 |
1730 | @@ -0,0 +1,446 @@ |
1731 | +.. _Management: |
1732 | + |
1733 | +Management |
1734 | +========== |
1735 | + |
1736 | +Akiban Persistit provides three main avenues for measuring and managing its internal resources: an RMI interface, a JMX interface and a command-line interface capable of launching various utility tasks. |
1737 | + |
1738 | +The RMI interface is primarily intended for the com.persistit.ui.AdminUI utility. AdminUI is a JFC/Swing program that runs on a device with graphical UI capabilities. For example, in Linux and Unix it requires an XServer. Since production servers are usually headless it is often necessary to run AdminUI remotely, via its RMI interface. To do this, the Persistit configuration must specify either the ``rmiport`` or ``rmihost`` property so that it can start an RMI server. |
1739 | + |
1740 | +Suppose a Persistit-based application is running on a host named “somehost” and has specified the configuration property ``rmiport=1099`` in its configuration. Then the AdminUI can be launched as follows to connect with it: |
1741 | + |
1742 | +.. code-block:: java |
1743 | + |
1744 | + java -cp classpath com.persistit.ui.AdminUI somehost:1099 |
1745 | + |
1746 | +where classpath includes the Persistit ``com.persistit.ui`` package. |
1747 | + |
1748 | +The JMX interface can be used by third-party management utilities, from applications such as ``jconsole`` and ``visualvm``, and from command-line JMX clients such as ``jmxterm``. To enable JMX access, the configuration must specify the property ``jmx=true``. This causes Persistit to register several MBeans with the platform MBean server during initialization. |
1749 | + |
1750 | +MXBeans |
1751 | +------- |
1752 | +The following JMX MXBeans are available: |
1753 | + |
1754 | + ``com.persistit:type=Persistit`` |
1755 | + See ``com.persistit.mxbeans.ManagementMXBean`` |
1756 | + ``com.persistit:type=Persistit,class=AlertMonitorMXBean`` |
1757 | + Accumulates, logs and emits notifications about abnormal events such as IOExceptions and measurements outside of |
1758 | + expected thresholds. |
1759 | + ``com.persistit:type=Persistit,class=CleanupManagerMXBean`` |
1760 | + View current state of the Cleanup Manager. The Cleanup Manager performs background pruning and tree maintenance |
1761 | + activities. |
1762 | + ``com.persistit:type=Persistit,class=IOMeter`` |
1763 | + Maintains statistics on file system I/O operations. |
1764 | + ``com.persistit.type=Persistit,class=JournalManager`` |
1765 | + Views current journal status. |
1766 | + ``com.persistit.type=Persistit,class=RecoveryManager`` |
1767 | + Views current status of the recovery process. Attributes of this MXBean change only during the recovery process. |
1768 | + ``com.persistit:type=Persistit,class=TransactionIndexMXBean`` |
1769 | + View internal state of transaction index queues and tables. |
1770 | + ``com.persistit.type=Persistit,class=BufferPool.*SSSS*`` |
1771 | + where *SSSS* is a buffer size (512, 1024, 2048, 4096 or 16394). View utilization statistics for buffers of the |
1772 | + selected size. |
1773 | + |
1774 | + |
1775 | +For details see the JavaDoc API documentation for each MXBean interface. |
1776 | + |
1777 | +Management Tasks |
1778 | +---------------- |
1779 | + |
1780 | +Persistit provides several ways to launch and administer ``com.persistit.Task`` instances. A ``Task`` is a management operation that may take a significant amount of time and usually runs in a separate thread. For example, ``com.persistit.IntegrityCheck`` is a ``Task`` that verifies the internal structural integrity of one or more trees and can run for minutes to hours, depending on the size of the database. The :ref:`AdminUI` tool, ``com.persistit.mxbeans.ManagementMXBean`` and the command-line interface (:ref:`CLI`) provide mechanisms to launch, suspend or stop a task, and to monitor a task’s progress. |
1781 | + |
1782 | +Currently the following built-in Tasks are available: |
1783 | + |
1784 | + ``icheck`` |
1785 | + Check the integrity of one or more trees or volumes. |
1786 | + ``save`` |
1787 | + Save selected key-value pairs from one or more trees to a flat file. |
1788 | + ``load`` |
1789 | + Load selected key-value pairs from a flat file written by ``save``. |
1790 | + ``backup`` |
1791 | + Control and/or perform a concurrent backup of one more more volumes. |
1792 | + ``stat`` |
1793 | + Aggregate various performance statistics and either return them immediately, or write them periodically to a file. |
1794 | + ``task`` |
1795 | + Check the status of an existing task. This task can also suspend, resume or stop an existing task. This task, which |
1796 | + immediately returns status information, can be used by external tools to poll the status of other tasks. |
1797 | + ``cliserver`` |
1798 | + Start a simple command-line server on a specified port. This enables a client program to execute commands sending |
1799 | + them directly to that port. |
1800 | + *other tasks* |
1801 | + Various commands allow you to select and view pages and journal records. |
1802 | + |
1803 | + |
1804 | +Executing a Task from an Application |
1805 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
1806 | + |
1807 | +The ``com.persistit.mxbeans.ManagementMXBean#execute`` and ``com.persistit.mxbeans.ManagementMXBean#launch`` methods both take a single String-valued argument, parse it to set up a ``Task`` and return a String-valued result. For example: |
1808 | + |
1809 | +.. code-block:: java |
1810 | + |
1811 | + String taskId = db.getManagement().launch(“backup -z file=/tmp/mybackup.zip”); |
1812 | + String status = db.getManagement().execute(“task -v -m -c taskId=” + taskId); |
1813 | + |
1814 | +launches the backup task and then queries its status. |
1815 | + |
1816 | +Executing a Task from a JMX Client |
1817 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
1818 | + |
1819 | +The ``com.persistit.mxbeans.ManagementMXBean#execute`` and ``com.persistit.mxbeans.ManagementMXBean#launch`` methods are exposed as operations on the ``com.persistit.mxbeans.ManagementMXBean``. You can invoke tasks |
1820 | + |
1821 | +- via ``jconsole`` by typing the desired command line as the argument of the ``execute`` operation. |
1822 | +- via a third-party JMX client such as ``jmxterm``. |
1823 | +- via the ``cliserver`` feature |
1824 | + |
1825 | +Executing a Task Using a Third-Party JMX client |
1826 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
1827 | + |
1828 | +You can use the ``jmxterm`` program, for example, (see [http://www.cyclopsgroup.org/projects/jmxterm]) to execute commands with the following shell script:: |
1829 | + |
1830 | + #!/bin/sh |
1831 | + java -jar jmxterm-1.0-alpha-4-uber.jar --verbose silent --noninteract --url $1 <<EOF |
1832 | + run -d com.persistit -b com.persistit:type=Persistit execute $2 |
1833 | + EOF |
1834 | + |
1835 | +To use this script, specify either the JMX URL or the process ID as the first command argument, and the command line as the second argument. Example:: |
1836 | + |
1837 | + peter:~/workspace/sandbox$ jmxterm-execute 1234 ‘stat\ -a’ |
1838 | + hit=3942334 miss=14 new=7364 evict=0 jwrite=81810 jread=2 jcopy=63848 tcommit=0 troll=0 CC=0 RV=12 RJ=2 WJ=81810 EV=0 FJ=529 IOkbytes=1134487 TOTAL |
1839 | + |
1840 | +This command invokes the ``stat`` task with the flag ``-a`` on a JVM running with process id 1234. Note that with jxmterm white-space must be quoted by backslash (‘\’) even though the argument list is also enclosed in single-quotes. The backslash marshals the space character through ``jmxterm``’s parser. Commas and other delimiters also need to be quoted. |
1841 | + |
1842 | +.. _cliserver: |
1843 | + |
1844 | +Executing a Task Using the Built-In ``cliserver`` |
1845 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
1846 | + |
1847 | +``cliserver`` is a simple text-based server that receives a command line as a text string and emits the generated output as its response. To start it, enter the command:: |
1848 | + |
1849 | + cliserver port=9999 |
1850 | + |
1851 | +programmatically or through JMX. (You may specify any valid, available port.) Then use a command-line client to send command lines to that port and display their results. Persistit includes a primitive command-line client within the ``com.persistit.CLI`` class itself. Create a script to invoke it as follows:: |
1852 | + |
1853 | + #!/bin/sh |
1854 | + java -cp classpath com.persistit.CLI localhost:9999 $* |
1855 | + |
1856 | +Where ``classpath`` includes the Persistit library. Assuming the name of the script is ``pcli`` you can then invoke commands from a shell as shown in this example:: |
1857 | + |
1858 | + /home/akiban:~$ pcli icheck -v -c "trees=*:Acc*" |
1859 | + Volume,Tree,Faults,IndexPages,IndexBytes,DataPages,DataBytes,LongRecordPages,LongRecordBytes,MvvPages,MvvRecords,MvvOverhead,MvvAntiValues,IndexHoles,PrunedPages |
1860 | + "persistit","AccumulatorRecoveryTest",0,3,24296,1519,15560788,0,0,1506,52192,721521,2397,0,0 |
1861 | + "*","*",0,3,24296,1519,15560788,0,0,1506,52192,721521,2397,0,0 |
1862 | + /home/akiban:~$ |
1863 | + |
1864 | +Alternatively, you can use ``curl`` as follows:: |
1865 | + |
1866 | + #!/bin/sh |
1867 | + echo "$*" | curl --silent --show-error telnet://localhost:9999 |
1868 | + |
1869 | +to issue commands. |
1870 | + |
1871 | +.. caution:: |
1872 | + |
1873 | + ``cliserver`` has no access control and sends potentially sensitive data in cleartext form. Therefore it should be used with care and only in a secure |
1874 | + network environment. Its primary mission is to allow easy inspection of internal data structures within Persistit. |
1875 | + |
1876 | +.. _CLI: |
1877 | + |
1878 | +The Command-Line Interface |
1879 | +-------------------------- |
1880 | + |
1881 | +The String value passed to the ``execute`` and ``launch`` operations specifies the name of a task and its arguments. The general form is:: |
1882 | + |
1883 | + commandname -flag -flag argname=value argname=value |
1884 | + |
1885 | +where the order of arguments and flags is not significant. |
1886 | + |
1887 | + |
1888 | +Command: ``icheck`` |
1889 | +^^^^^^^^^^^^^^^^^^^ |
1890 | + |
1891 | +Performs a com.persistit.IntegrityCheck task. Arguments: |
1892 | + |
1893 | + ``trees`` |
1894 | + Specifies volumes and/or trees to check. See com.persistit.TreeSelector for details syntax. Default is all trees in all volumes. |
1895 | + ``-r`` |
1896 | + Tree specification uses Java RegEx syntax (Default is to treat ‘*’ and ‘?’ as standard single-character and multi-character wildcards. |
1897 | + ``-u`` |
1898 | + Don't freeze updates (Default is to freeze updates) |
1899 | + ``-h`` |
1900 | + Fix index holes. An *index hole* is an anomaly that occurs rarely in normal operation such that a page does not have an index entry in the index page level |
1901 | + immediately above it |
1902 | + ``-p`` |
1903 | + Prune obsolete MVV (multi-version value) instances while checking. |
1904 | + ``-P`` |
1905 | + Prune obsolete MVV instances, and clear any remaining aborted TransactionStatus instances. Use with care. |
1906 | + ``-v`` |
1907 | + Emit verbose output. For example, emit statistics for each tree. |
1908 | + ``-c`` |
1909 | + Display tree statistics in comma-separated-variable format suitable for import into a spreadsheet program. |
1910 | + |
1911 | +Example:: |
1912 | + |
1913 | + icheck trees=vehicles/* -h |
1914 | + |
1915 | +Checks all trees in the ``vehicles`` volume and repairs index holes. |
1916 | + |
1917 | +Command: ``save`` |
1918 | +^^^^^^^^^^^^^^^^^ |
1919 | + |
1920 | +Starts a com.persistit.StreamSaver task. Arguments: |
1921 | + |
1922 | + ``file`` |
1923 | + Name of file to save records to (required) |
1924 | + ``trees`` |
1925 | + Specifies volumes and/or trees to save. See com.persistit.TreeSelector for details syntax. Default is all trees in all volumes. |
1926 | + ``-r`` |
1927 | + Tree specification uses Java RegEx syntax (Default is to treat ‘*’ and ‘?’ as standard single-character and multi-character wildcards.) |
1928 | + ``-v`` |
1929 | + emit verbose output |
1930 | + |
1931 | +...‘*’ and ‘?’ are standard wildcards. |
1932 | + |
1933 | +Example:: |
1934 | + |
1935 | + save -v file=/home/akiban/save.dat trees=vehicles/*{[“Edsel”:”Yugo”]} |
1936 | + |
1937 | +Saves the records for “Edsel” through “Yugo”, inclusive, from any tree in the volume named ``vehicles``. See com.persistit.TreeSelector for selection syntax details. |
1938 | + |
1939 | +Command: ``load`` |
1940 | +^^^^^^^^^^^^^^^^^ |
1941 | + |
1942 | +Starts a com.persistit.StreamLoader task. Arguments: |
1943 | + |
1944 | + ``file`` |
1945 | + Name of file to load records from |
1946 | + ``trees`` |
1947 | + Specifies volumes and/or trees to load. See com.persistit.TreeSelector for details syntax. Default is all trees in all volumes. |
1948 | + ``-r`` |
1949 | + Tree specification uses Java RegEx syntax (Default is to treat ‘*’ and ‘?’ as standard single-character and multi-character wildcards.) |
1950 | + ``-n`` |
1951 | + Don't create missing Volumes (Default is to create them) |
1952 | + ``-t`` |
1953 | + Don't create missing Trees (Default is to create them) |
1954 | + ``-v`` |
1955 | + Emit verbose output |
1956 | + |
1957 | +...‘*’ and ‘?’ are standard wildcards. |
1958 | + |
1959 | +Example:: |
1960 | + |
1961 | + load file=/home/akiban/save.dat trees=*/*{[“Falcon”:”Firebird”]} |
1962 | + |
1963 | +For any tree in any volume, this command loads all records having keys between “Falcon” and “Firebird”, inclusive. |
1964 | + |
1965 | +Command: ``backup`` |
1966 | +^^^^^^^^^^^^^^^^^^^ |
1967 | + |
1968 | +Starts a ``com.persistit.BackupTask`` task to perform concurrent (hot) backup. Arguments: |
1969 | + |
1970 | + ``file`` |
1971 | + Archive file path. If this argument is specified, BackupTask will back up the database in .zip format to the specified file. This is intended only for small |
1972 | + databases. It is expected that ``backup`` will be used in conjunction with high-speed third-party data copying utilities for production use. The ``-a`` and |
1973 | + ``-e`` |
1974 | + flags are incompatible with operation when the ``file`` argument is specified and are ignored. |
1975 | + ``-a`` |
1976 | + Start appendOnly mode - for use with third-party backup tools. ``backup -a`` should be invoked before data copying begins. |
1977 | + ``-e`` |
1978 | + End appendOnly mode - for use with third-party backup tools. ``backup -e`` should be invoked after data copying ends. |
1979 | + ``-c`` |
1980 | + Request checkpoint before backup. |
1981 | + ``-z`` |
1982 | + Compress output to ZIP format - meaningful only in conjunction with the ``file`` argument. |
1983 | + ``-f`` |
1984 | + Emit a list of files that need to be copied. In this form the task immediately returns with a list of files currently comprising the Persistit database, |
1985 | + including Volume and journal files. |
1986 | + ``-y`` |
1987 | + Copy pages from journal to Volumes before starting backup. This reduces the number of journal files in the backup set. |
1988 | + |
1989 | +Example:: |
1990 | + |
1991 | + backup -y -a -c -y -f |
1992 | + … invoke third-party backup tool to copy the database files |
1993 | + backup -e |
1994 | + |
1995 | +Uses the ``backup`` task twice, once to set *append-only* mode, checkpoint the journal and perform a full copy-back cycle (a process that attempts to shorten the journal), and then write out a list of files that need to be copied. The second call to ``backup`` restores normal operation. Between these two calls a third party backup tool is used to copy the data. |
1996 | + |
1997 | +Example:: |
1998 | + |
1999 | + backup -z file=/tmp/my_backup.zip |
2000 | + |
2001 | +Uses the built-in file copy feature with ZIP compression. |
2002 | + |
2003 | +Command: ``task`` |
2004 | +^^^^^^^^^^^^^^^^^ |
2005 | + |
2006 | +Queries, stops, suspends or resumes a background task. Arguments: |
2007 | + |
2008 | + ``taskId`` |
2009 | + Task ID to to check, or -1 for all |
2010 | + ``-v`` |
2011 | + Verbose - returns detailed status messages from the selected task(s) |
2012 | + ``-m`` |
2013 | + Keep previously delivered messages. Default is to remove messages once reported. |
2014 | + ``-k`` |
2015 | + Keep the selected task or tasks even if completed. Default is to remove tasks once reported. |
2016 | + ``-x`` |
2017 | + Stop the selected task or tasks |
2018 | + ``-u`` |
2019 | + Suspend the selected task or tasks |
2020 | + ``-r`` |
2021 | + Resume the selected task or tasks |
2022 | + |
2023 | +Unlike other commands, the ``task`` command always runs immediately even if invoked through the ``launch`` method. |
2024 | + |
2025 | +You can use the ``task`` command to poll and display progress of long-running tasks. Invoke:: |
2026 | + |
2027 | + task -v -m -c taskId=nnn |
2028 | + |
2029 | +until the result is empty. |
2030 | + |
2031 | +Command: ``cliserver`` |
2032 | +^^^^^^^^^^^^^^^^^^^^^^ |
2033 | + |
2034 | +Starts a simple text-based server that receives a command line as a text string and emits the generated output as its response. Argument: |
2035 | + |
2036 | + ``port`` |
2037 | + Port number on which to listen for commands. |
2038 | + |
2039 | +Command: ``exit`` |
2040 | +^^^^^^^^^^^^^^^^^ |
2041 | + |
2042 | +Ends a running ``cliserver`` instance. |
2043 | + |
2044 | +Commands for Viewing Data |
2045 | +^^^^^^^^^^^^^^^^^^^^^^^^^ |
2046 | + |
2047 | +The following commands execute immediately, even if invoked through the ``launch`` method. They provide a mechanism to examine individual database pages or journal records. |
2048 | + |
2049 | +Command: ``select`` |
2050 | +^^^^^^^^^^^^^^^^^^^ |
2051 | + |
2052 | +Selects a volume and optionally a tree for subsequent operations such as ``view``. Arguments: |
2053 | + |
2054 | + ``tree`` |
2055 | + Specifies volume and/or tree to select as context for subsequent operations. See com.persistit.TreeSelector for details syntax. |
2056 | + ``-r`` |
2057 | + Tree specification uses Java RegEx syntax (Default is to treat ‘*’ and ‘?’ as standard single-character and multi-character wildcards.) |
2058 | + |
2059 | +Command: ``list`` |
2060 | +^^^^^^^^^^^^^^^^^ |
2061 | + |
2062 | +Lists volumes and trees. Arguments: |
2063 | + |
2064 | + ``trees`` |
2065 | + Specifies volumes and/or trees to list. See com.persistit.TreeSelector for details syntax. Default is all trees in all volumes. |
2066 | + ``-r`` |
2067 | + Tree specification uses Java RegEx syntax (Default is to treat ‘*’ and ‘?’ as standard single-character and multi-character wildcards. |
2068 | + |
2069 | +All volumes, and all trees within those volumes, that match the ``trees`` specification are listed. By default, this command lists all trees in all volumes. |
2070 | + |
2071 | +Command: ``pview`` |
2072 | +^^^^^^^^^^^^^^^^^^ |
2073 | + |
2074 | +Displays contents of a database page. Arguments: |
2075 | + |
2076 | + ``page`` |
2077 | + page address |
2078 | + ``jaddr`` |
2079 | + journal address - displays a page version stored at the specified journal address |
2080 | + ``key`` |
2081 | + a key specified as a String defined in the com.persistit.Key class |
2082 | + ``level`` |
2083 | + tree level of the desired page |
2084 | + ``find`` |
2085 | + selected records in an index page surrounding a key that points to the specified page address |
2086 | + ``-a`` |
2087 | + all records. If specified, all records in the page will be displayed. Otherwise the output is abbreviated to no more than 20 lines. |
2088 | + ``-s`` |
2089 | + summary - only header information in the page is displayed |
2090 | + |
2091 | +The ``pview`` command identifies a page in one of three distinct ways: by page address, by journal address, or by key. Only one of the three parameters ``page``, ``jaddr`` or ``key`` (with ``level``) may be used. |
2092 | + |
2093 | +``page`` specifies the current version of a page having the specified address. If there is a copy of the page in the buffer pool, that copy is displayed even if it contains updates that are not yet written to disk. |
2094 | + |
2095 | +``jaddr`` specifies an address in the journal. Typical use is to invoke the ``jview`` command to view a list of journal records, and then to see a detailed view of one page record in the journal, invoke the ``pview`` command with its journal address. |
2096 | + |
2097 | +``key`` specifies a key. By default the data page associated with that key will be displayed. The data page is defined as level 0. The ``level`` parameter allows pages at various index levels to be viewed; for example ``level=1`` refers to the index page that points to the data page containing the specified key. |
2098 | + |
2099 | +When examining an index page with potentially hundreds of records it is sometimes convenient to find the record that points to a particular child page, and also the records immediately before and after. Specifying the ``find`` parameter when viewing an index page abbreviates the displayed records to include just the first and last records in the page, plus a small range of records surrounding the one that points to the specified page. This mechanism provides a convenient way to find sibling pages. |
2100 | + |
2101 | + |
2102 | +Command: ``path`` |
2103 | +^^^^^^^^^^^^^^^^^ |
2104 | + |
2105 | +For a specified key displays the sequence of pages from root of the tree to the data page containing they key. Argument: |
2106 | + |
2107 | + ``key`` |
2108 | + a key specified as a String defined in the com.persistit.Key class |
2109 | + |
2110 | + |
2111 | +Command: ``jview`` |
2112 | +^^^^^^^^^^^^^^^^^^ |
2113 | + |
2114 | +Displays journal records. Arguments: |
2115 | + |
2116 | + ``start`` |
2117 | + starting journal address (default = 0) |
2118 | + ``end`` |
2119 | + end journal address (address = infinite) |
2120 | + ``timestamps`` |
2121 | + range selection of timestamp values, e.g., “132466-132499” for records having timestamps between these two numbers, inclusive. Default is all timestamps. |
2122 | + ``types`` |
2123 | + comma-delimted list of two-character record types, e.g., “JH,IV,IT,CP” to select only Journal Header, Identify Volume, Identify Tree and Check Point records |
2124 | + (see ``com.persistit.JournalRecord`` for definitions of all types.) Default value is all types. |
2125 | + ``pages`` |
2126 | + range selection of page address for PA (Page) records, e.g., “1,2,13-16” to include pages, 1, 2, 13, 14, 15 or 16. |
2127 | + ``maxkey`` |
2128 | + maximum display length of key values in the output. Default value is 42. |
2129 | + ``maxvalue`` |
2130 | + maximum display length of values in the output. Default value is 42. |
2131 | + ``path`` |
2132 | + journal file path. Default is the journal file path of the currently instantiated Persistit instance. |
2133 | + ``-v`` |
2134 | + verbose format. If specified, causes PM (Page Map) and TM (TransactionMap) records to be be display all map elements. |
2135 | + |
2136 | + |
2137 | +Note that the journal on a busy system contains a large number of records, so entering the ``journal`` command without constraining the address range or record types may result in extremely lengthy output. |
2138 | + |
2139 | +Command: ``open`` |
2140 | +^^^^^^^^^^^^^^^^^ |
2141 | + |
2142 | +Opens a Persistit database for analysis. This task can only be used to examine a copy of a Persistit database that is not currently in use by an application. It works by attempting to open the volume and journal files using a synthesized configuration. It finds a collection of journal files and volume files specified by the ``datapath``, ``journalpath`` and ``volumepath`` arguments; from these it derives a set of properties that will allow it to examine those journals and volumes. By default all volumes are opened in read-only mode and cannot be changed by operations executed from the command-line interface. |
2143 | + |
2144 | +If there already is an open Persistit instance, this command detaches it. For example, if you start ``cliserver`` from a live Persistit instance and then issue the ``open`` command, the live instance will continue to operate but ``cliserver`` will no longer be attached to it. |
2145 | + |
2146 | +Note that you cannot ``open`` volumes that are already open in a running Persistit instance due to their file locks. However, you can copy open volumes and journal files to another location and ``open`` the copy. This is the primary use case for the ``open`` command: to analyze a copy of a database (for example a copy recovered from backup) without having to a launch the application software that embeds Persistit. |
2147 | + |
2148 | +Arguments: |
2149 | + |
2150 | + ``datapath`` |
2151 | + a directory path for volume and journal files to be analyzed |
2152 | + ``volumepath`` |
2153 | + overrides ``datapath`` to specify an alternative location for volume files. |
2154 | + ``journalpath`` |
2155 | + overrides ``datapath`` to specify an alternative location for journal files. |
2156 | + ``rmiport`` |
2157 | + specifies an RMI port to which an instance of the AdminUI can attach. |
2158 | + ``-g`` |
2159 | + launch a local copy of AdminUI |
2160 | + ``-y`` |
2161 | + attempt to recover committed transactions . |
2162 | + |
2163 | +Note that even if you specify ``-y`` to recover transactions, the volume files will not be modified. But the ``open`` command will add a new journal file containing modifications caused by the recovery process. You can simply delete that file when done. |
2164 | + |
2165 | +Command: ``close`` |
2166 | +^^^^^^^^^^^^^^^^^^ |
2167 | + |
2168 | +Detach and close the current Persistit instance. If the CLI was started with a live Persistit instance then this command merely detaches from it; if the instance was created with the ``open`` command then ``close`` closes it and releases all related file locks, buffers, etc. |
2169 | + |
2170 | +Command: ``source`` |
2171 | +^^^^^^^^^^^^^^^^^^^ |
2172 | + |
2173 | +Execute command lines from a specified text file. Argument: |
2174 | + |
2175 | + ``file`` |
2176 | + file name of command input file |
2177 | |
2178 | === removed file 'doc/Management.txt' |
2179 | --- doc/Management.txt 2012-04-30 22:09:31 +0000 |
2180 | +++ doc/Management.txt 1970-01-01 00:00:00 +0000 |
2181 | @@ -1,360 +0,0 @@ |
2182 | -[[Management]] |
2183 | -= Management |
2184 | - |
2185 | -Akiban Persistit provides three main avenues for measuring and managing its internal resources: an RMI interface, a JMX interface and a command-line interface capable of launching various utility tasks. |
2186 | - |
2187 | -The RMI interface is primarily intended for the com.persistit.ui.AdminUI utility. AdminUI is a JFC/Swing program that runs on a device with graphical UI capabilities. For example, in Linux and Unix it requires an XServer. Since production servers are usually headless it is often necessary to run AdminUI remotely, via its RMI interface. To do this, the Persistit configuration must specify either the +rmiport+ or +rmihost+ property so that it can start an RMI server. |
2188 | - |
2189 | -Suppose a Persistit-based application is running on a host named “somehost” and has specified the configuration property +rmiport=1099+ in its configuration. Then the AdminUI can be launched as follows to connect with it: |
2190 | - |
2191 | ----- |
2192 | -java -cp <classpath> com.persistit.ui.AdminUI somehost:1099 |
2193 | ----- |
2194 | - |
2195 | -where <classpath> includes the Persistit com.persistit.ui package. |
2196 | - |
2197 | -The JMX interface can be used by third-party management utilities, from applications such as +jconsole+ and +visualvm+, and from command-line JMX clients such as +jmxterm+. To enable JMX access, the configuration must specify the property +jmx=true+. This causes Persistit to register several MBeans with the platform MBean server during initialization. |
2198 | - |
2199 | -== MXBeans |
2200 | - |
2201 | -The following JMX MXBeans are available: |
2202 | - |
2203 | -[horizontal] |
2204 | -+com.persistit:type=Persistit+:: See +com.persistit.mxbeans.ManagementMXBean+ |
2205 | -+com.persistit:type=Persistit,class=AlertMonitorMXBean+:: Accumulates, logs and emits notifications about abnormal events such as IOExceptions and measurements outside of expected thresholds. |
2206 | -+com.persistit:type=Persistit,class=CleanupManagerMXBean+:: View current state of the Cleanup Manager. The Cleanup Manager performs background pruning and tree maintenance activities. |
2207 | -+com.persistit:type=Persistit,class=IOMeter+:: Maintains statistics on file system I/O operations. |
2208 | -+com.persistit.type=Persistit,class=JournalManager+:: Views current journal status. |
2209 | -+com.persistit.type=Persistit,class=RecoveryManager+:: Views current status of the recovery process. Attributes of this MXBean change only during the recovery process. |
2210 | -+com.persistit:type=Persistit,class=TransactionIndexMXBean+:: View internal state of transaction index queues and tables. |
2211 | -+com.persistit.type=Persistit,class=BufferPool._SSSS_+:: where _SSSS_ is a buffer size (512, 1024, 2048, 4096 or 16394). View utilization statistics for buffers of the selected size. |
2212 | - |
2213 | - |
2214 | -For details see the JavaDoc API documentation for each MXBean interface. |
2215 | - |
2216 | -== Management Tasks |
2217 | - |
2218 | -Persistit provides several ways to launch and administer +com.persistit.Task+ instances. A +Task+ is a management operation that may take a significant amount of time and usually runs in a separate thread. For example, +com.persistit.IntegrityCheck+ is a +Task+ that verifies the internal structural integrity of one or more trees and can run for minutes to hours, depending on the size of the database. The <<AdminUI>> tool, +com.persistit.ManagementMXBean+ and the command-line interface (<<CLI>>) provide mechanisms to launch, suspend or stop a task, and to monitor a task’s progress. |
2219 | - |
2220 | -Currently the following built-in Tasks are available: |
2221 | - |
2222 | -[horizontal] |
2223 | -+icheck+:: Check the integrity of one or more trees or volumes. |
2224 | -+save+:: Save selected key-value pairs from one or more trees to a flat file. |
2225 | -+load+:: Load selected key-value pairs from a flat file written by +save+. |
2226 | -+backup+:: Control and/or perform a concurrent backup of one more more volumes. |
2227 | -+stat+:: Aggregate various performance statistics and either return them immediately, or write them periodically to a file. |
2228 | -+task+:: Check the status of an existing task. This task can also suspend, resume or stop an existing task. This task, which immediately returns status information, can be used by external tools to poll the status of other tasks. |
2229 | -+cliserver+:: Start a simple command-line server on a specified port. This enables a client program to execute commands sending them directly to that port. |
2230 | -+_other tasks_+:: Various commands allow you to select and view pages and journal records. |
2231 | - |
2232 | - |
2233 | -=== Executing a Task from an Application |
2234 | - |
2235 | -The +com.persistit.mxbeans.ManagementMXBean#execute+ and +com.persistit.mxbeans.ManagementMXBean#launch+ methods both take a single String-valued argument, parse it to set up a +Task+ and return a String-valued result. For example: |
2236 | - |
2237 | -[source,java] |
2238 | ----- |
2239 | -String taskId = db.getManagement().launch(“backup -z file=/tmp/mybackup.zip”); |
2240 | -String status = db.getManagement().execute(“task -v -m -c taskId=” + taskId); |
2241 | ----- |
2242 | - |
2243 | -launches the backup task and then queries its status. |
2244 | - |
2245 | -=== Executing a Task from a JMX Client |
2246 | - |
2247 | -The +com.persistit.mxbeans.ManagementMXBean#execute+ and +com.persistit.mxbeans.ManagementMXBean#launch+ methods are exposed as operations on the +com.persistit.mxbeans.ManagementMXBean+. You can invoke tasks |
2248 | - |
2249 | -- via +jconsole+ by typing the desired command line as the argument of the +execute+ operation. |
2250 | -- via a third-party JMX client such as +jmxterm+. |
2251 | -- via the +cliserver+ feature |
2252 | - |
2253 | -==== Executing a Task Using a Third-Party JMX client. |
2254 | - |
2255 | -You can use the +jmxterm+ program, for example, (see [http://www.cyclopsgroup.org/projects/jmxterm]) to execute commands with the following shell script: |
2256 | - |
2257 | -[source,bash] |
2258 | ----- |
2259 | -#!/bin/sh |
2260 | -java -jar jmxterm-1.0-alpha-4-uber.jar --verbose silent --noninteract --url $1 <<EOF |
2261 | -run -d com.persistit -b com.persistit:type=Persistit execute $2 |
2262 | -EOF |
2263 | ----- |
2264 | - |
2265 | -To use this script, specify either the JMX URL or the process ID as the first command argument, and the command line as the second argument. Example |
2266 | - |
2267 | ----- |
2268 | -peter:~/workspace/sandbox$ jmxterm-execute 1234 ‘stat\ -a’ |
2269 | -hit=3942334 miss=14 new=7364 evict=0 jwrite=81810 jread=2 jcopy=63848 tcommit=0 troll=0 CC=0 RV=12 RJ=2 WJ=81810 EV=0 FJ=529 IOkbytes=1134487 TOTAL |
2270 | ----- |
2271 | - |
2272 | -This command invokes the +stat+ task with the flag +-a+ on a JVM running with process id 1234. Note that with jxmterm white-space must be quoted by backslash (‘\’) even though the argument list is also enclosed in single-quotes. The backslash marshals the space character through +jmxterm+’s parser. Commas and other delimiters also need to be quoted. |
2273 | - |
2274 | -[[cliserver]] |
2275 | -=== Executing a Task Using the Built-In +cliserver+ |
2276 | - |
2277 | -+cliserver+ is a simple text-based server that receives a command line as a text string and emits the generated output as its response. To start it, enter the command |
2278 | ----- |
2279 | -cliserver port=9999 |
2280 | ----- |
2281 | -programmatically or through JMX. (You may specify any valid, available port.) Then use a command-line client to send command lines to that port and display their results. Persistit includes a primitive command-line client within the +com.persistit.CLI+ class itself. Create a script to invoke it as follows: |
2282 | - |
2283 | -[source,bash] |
2284 | ----- |
2285 | -#!/bin/sh |
2286 | -java -cp <classpath> com.persistit.CLI localhost:9999 $* |
2287 | ----- |
2288 | - |
2289 | -Where +<classpath>+ includes the Persistit library. Assuming the name of the script is +pcli+ you can then invoke commands from a shell as shown in this example: |
2290 | - |
2291 | ----- |
2292 | -/home/akiban:~$ pcli icheck -v -c "trees=*:Acc*" |
2293 | -Volume,Tree,Faults,IndexPages,IndexBytes,DataPages,DataBytes,LongRecordPages,LongRecordBytes,MvvPages,MvvRecords,MvvOverhead,MvvAntiValues,IndexHoles,PrunedPages |
2294 | -"persistit","AccumulatorRecoveryTest",0,3,24296,1519,15560788,0,0,1506,52192,721521,2397,0,0 |
2295 | -"*","*",0,3,24296,1519,15560788,0,0,1506,52192,721521,2397,0,0 |
2296 | -/home/akiban:~$ |
2297 | ----- |
2298 | - |
2299 | -Alternatively, you can use +curl+ as follows: |
2300 | - |
2301 | -[source,bash] |
2302 | ----- |
2303 | -#!/bin/sh |
2304 | -echo "$*" | curl --silent --show-error telnet://localhost:9999 |
2305 | ----- |
2306 | -to issue commands. |
2307 | - |
2308 | -CAUTION: Warning: +cliserver+ has no access control and sends potentially sensitive data in cleartext form. Therefore it should be used with care and only in a secure network environment. Its primary mission is to allow easy inspection of internal data structures within Persistit. |
2309 | - |
2310 | -[[CLI]] |
2311 | -== The Command-Line Interface |
2312 | - |
2313 | -The String value passed to the +execute+ and +launch+ operations specifies the name of a task and its arguments. The general form is |
2314 | - |
2315 | ----- |
2316 | -commandname -flag -flag argname=value argname=value |
2317 | ----- |
2318 | - |
2319 | -where the order of arguments and flags is not significant. |
2320 | - |
2321 | - |
2322 | -=== Command: +icheck+ |
2323 | - |
2324 | -Performs a com.persistit.IntegrityCheck task. Arguments: |
2325 | - |
2326 | -[horizontal] |
2327 | -+trees+:: Specifies volumes and/or trees to check. See com.persistit.TreeSelector for details syntax. Default is all trees in all volumes. |
2328 | -+-r+:: Tree specification uses Java RegEx syntax (Default is to treat ‘*’ and ‘?’ as standard single-character and multi-character wildcards. |
2329 | -+-u+:: Don't freeze updates (Default is to freeze updates) |
2330 | -+-h+:: Fix index holes. An _index hole_ is an anomaly that occurs rarely in normal operation such that a page does not have an index entry in the index page level immediately above it |
2331 | -+-p+:: Prune obsolete MVV (multi-version value) instances while checking. |
2332 | -+-P+:: Prune obsolete MVV instances, and clear any remaining aborted TransactionStatus instances. Use with care. |
2333 | -+-v+:: Emit verbose output. For example, emit statistics for each tree. |
2334 | -+-c+:: Display tree statistics in comma-separated-variable format suitable for import into a spreadsheet program. |
2335 | - |
2336 | -Example: |
2337 | ----- |
2338 | -icheck trees=vehicles/* -h |
2339 | ----- |
2340 | -Checks all trees in the +vehicles+ volume and repairs index holes. |
2341 | - |
2342 | -=== Command: +save+ |
2343 | - |
2344 | -Starts a com.persistit.StreamSaver task. Arguments: |
2345 | - |
2346 | -[horizontal] |
2347 | -+file+:: Name of file to save records to (required) |
2348 | -+trees+:: Specifies volumes and/or trees to save. See com.persistit.TreeSelector for details syntax. Default is all trees in all volumes. |
2349 | -+-r+:: Tree specification uses Java RegEx syntax (Default is to treat ‘*’ and ‘?’ as standard single-character and multi-character wildcards.) |
2350 | -+-v+:: emit verbose output |
2351 | -‘*’ and ‘?’ as standard wildcards.) |
2352 | - |
2353 | -Example: |
2354 | ----- |
2355 | -save -v file=/home/akiban/save.dat trees=vehicles/*{[“Edsel”:”Yugo”]} |
2356 | ----- |
2357 | - |
2358 | -Saves the records for “Edsel” through “Yugo”, inclusive, from any tree in the volume named +vehicles+. See com.persistit.TreeSelector for selection syntax details. |
2359 | - |
2360 | -=== Command: +load+ |
2361 | - |
2362 | -Starts a com.persistit.StreamLoader task. Arguments: |
2363 | - |
2364 | -[horizontal] |
2365 | -+file+:: Name of file to load records from |
2366 | -+trees+:: Specifies volumes and/or trees to load. See com.persistit.TreeSelector for details syntax. Default is all trees in all volumes. |
2367 | -+-r+:: Tree specification uses Java RegEx syntax (Default is to treat ‘*’ and ‘?’ as standard single-character and multi-character wildcards.) |
2368 | -+-n+:: Don't create missing Volumes (Default is to create them) |
2369 | -+-t+:: Don't create missing Trees (Default is to create them) |
2370 | -‘*’ and ‘?’ as standard wildcards.) |
2371 | -+-v+:: emit verbose output |
2372 | - |
2373 | -Example: |
2374 | ----- |
2375 | -load file=/home/akiban/save.dat trees=*/*{[“Falcon”:”Firebird”]} |
2376 | ----- |
2377 | - |
2378 | -For any tree in any volume, this command loads all records having keys between “Falcon” and “Firebird”, inclusive. |
2379 | - |
2380 | -=== Command: +backup+ |
2381 | - |
2382 | -Starts a +com.persistit.BackupTask+ task to perform concurrent (hot) backup. Arguments: |
2383 | - |
2384 | -[horizontal] |
2385 | -+file+:: Archive file path. If this argument is specified, BackupTask will back up the database in .zip format to the specified file. This is intended only for small databases. It is expected that +backup+ will be used in conjunction with high-speed third-party data copying utilities for production use. The +-a+ and +-e+ flags are incompatible with operation when the +file+ argument is specified and are ignored. |
2386 | -+-a+:: Start appendOnly mode - for use with third-party backup tools. +backup -a+ should be invoked before data copying begins. |
2387 | -+-e+:: End appendOnly mode - for use with third-party backup tools. +backup -e+ should be invoked after data copying ends. |
2388 | -+-c+:: Request checkpoint before backup. |
2389 | -+-z+:: Compress output to ZIP format - meaningful only in conjunction with the +file+ argument. |
2390 | -+-f+:: Emit a list of files that need to be copied. In this form the task immediately returns with a list of files currently comprising the Persistit database, including Volume and journal files. |
2391 | -+-y+:: Copy pages from journal to Volumes before starting backup. This reduces the number of journal files in the backup set. |
2392 | - |
2393 | -Examples: |
2394 | ----- |
2395 | -backup -y -a -c -y -f |
2396 | -… invoke third-party backup tool to copy the database files |
2397 | -backup -e |
2398 | ----- |
2399 | -Uses the +backup+ task twice, once to set _append-only_ mode, checkpoint the journal and perform a full copy-back cycle (a process that attempts to shorten the journal), and then write out a list of files that need to be copied. The second call to +backup+ restores normal operation. Between these two calls a third party backup tool is used to copy the data. |
2400 | - |
2401 | ----- |
2402 | -backup -z file=/tmp/my_backup.zip |
2403 | ----- |
2404 | -Uses the built-in file copy feature with ZIP compression. |
2405 | - |
2406 | -=== Command: +task+ |
2407 | - |
2408 | -Queries, stops, suspends or resumes a background task. Arguments: |
2409 | - |
2410 | -[horizontal] |
2411 | -+taskId+:: Task ID to to check, or -1 for all |
2412 | -+-v+:: Verbose - returns detailed status messages from the selected task(s) |
2413 | -+-m+:: Keep previously delivered messages. Default is to remove messages once reported. |
2414 | -+-k+:: Keep the selected task or tasks even if completed. Default is to remove tasks once reported. |
2415 | -+-x+:: Stop the selected task or tasks |
2416 | -+-u+:: Suspend the selected task or tasks |
2417 | -+-r+:: Resume the selected task or tasks |
2418 | - |
2419 | -Unlike other commands, the +task+ command always runs immediately even if invoked through the +launch+ method. |
2420 | - |
2421 | -You can use the +task+ command to poll and display progress of long-running tasks. Invoke |
2422 | - |
2423 | ----- |
2424 | -task -v -m -c taskId=nnn |
2425 | ----- |
2426 | - |
2427 | -until the result is empty. |
2428 | - |
2429 | -=== Command: +cliserver+ |
2430 | - |
2431 | -Starts a simple text-based server that receives a command line as a text string and emits the generated output as its response. Argument: |
2432 | - |
2433 | -[horizontal] |
2434 | -+port+:: Port number on which to listen for commands. |
2435 | - |
2436 | -=== Command: +exit+ |
2437 | - |
2438 | -Ends a running +cliserver+ instance. |
2439 | - |
2440 | -== Commands for Viewing Data |
2441 | - |
2442 | -The following commands execute immediately, even if invoked through the +launch+ method. They provide a mechanism to examine individual database pages or journal records. |
2443 | - |
2444 | -=== Command: +select+ |
2445 | - |
2446 | -Selects a volume and optionally a tree for subsequent operations such as +view+. Arguments: |
2447 | - |
2448 | -[horizontal] |
2449 | -+tree+:: Specifies volume and/or tree to select as context for subsequent operations. See com.persistit.TreeSelector for details syntax. |
2450 | -+-r+:: Tree specification uses Java RegEx syntax (Default is to treat ‘*’ and ‘?’ as standard single-character and multi-character wildcards.) |
2451 | - |
2452 | -=== Command: +list+ |
2453 | - |
2454 | -Lists volumes and trees. Arguments: |
2455 | - |
2456 | -[horizontal] |
2457 | -+trees+:: Specifies volumes and/or trees to list. See com.persistit.TreeSelector for details syntax. Default is all trees in all volumes. |
2458 | -+-r+:: Tree specification uses Java RegEx syntax (Default is to treat ‘*’ and ‘?’ as standard single-character and multi-character wildcards. |
2459 | - |
2460 | -All volumes, and all trees within those volumes, that match the +trees+ specification are listed. By default, this command lists all trees in all volumes. |
2461 | - |
2462 | -=== Command: +pview+ |
2463 | - |
2464 | -Displays contents of a database page. Arguments: |
2465 | - |
2466 | -[horizontal] |
2467 | -+page+:: page address |
2468 | -+jaddr+:: journal address - displays a page version stored at the specified journal address |
2469 | -+key+:: a key specified as a String defined in the com.persistit.Key class |
2470 | -+level+:: tree level of the desired page |
2471 | -+find+:: selected records in an index page surrounding a key that points to the specified page address |
2472 | -+-a+:: all records. If specified, all records in the page will be displayed. Otherwise the output is abbreviated to no more than 20 lines. |
2473 | -+-s+:: summary - only header information in the page is displayed |
2474 | - |
2475 | -The +pview+ command identifies a page in one of three distinct ways: by page address, by journal address, or by key. Only one of the three parameters +page+, +jaddr+ or +key+ (with +level+) may be used. |
2476 | - |
2477 | -+page+ specifies the current version of a page having the specified address. If there is a copy of the page in the buffer pool, that copy is displayed even if it contains updates that are not yet written to disk. |
2478 | - |
2479 | -+jaddr+ specifies an address in the journal. Typical use is to invoke the +jview+ command to view a list of journal records, and then to see a detailed view of one page record in the journal, invoke the +pview+ command with its journal address. |
2480 | - |
2481 | -+key+ specifies a key. By default the data page associated with that key will be displayed. The data page is defined as level 0. The +level+ parameter allows pages at various index levels to be viewed; for example +level=1+ refers to the index page that points to the data page containing the specified key. |
2482 | - |
2483 | -When examining an index page with potentially hundreds of records it is sometimes convenient to find the record that points to a particular child page, and also the records immediately before and after. Specifying the +find+ parameter when viewing an index page abbreviates the displayed records to include just the first and last records in the page, plus a small range of records surrounding the one that points to the specified page. This mechanism provides a convenient way to find sibling pages. |
2484 | - |
2485 | - |
2486 | -=== Command: +path+ |
2487 | - |
2488 | -For a specified key displays the sequence of pages from root of the tree to the data page containing they key. Argument: |
2489 | - |
2490 | -[horizontal] |
2491 | -+key+:: a key specified as a String defined in the com.persistit.Key class |
2492 | - |
2493 | - |
2494 | -=== Command: +jview+ |
2495 | - |
2496 | -Displays journal records. Arguments: |
2497 | - |
2498 | -[horizontal] |
2499 | -+start+:: starting journal address (default = 0) |
2500 | -+end+:: end journal address (address = infinite) |
2501 | -+timestamps+:: range selection of timestamp values, e.g., “132466-132499” for records having timestamps between these two numbers, inclusive. Default is all timestamps. |
2502 | -+types+:: comma-delimted list of two-character record types, e.g., “JH,IV,IT,CP” to select only Journal Header, Identify Volume, Identify Tree and Check Point records (see com.persistit.JournalRecord for definitions of all types.) Default value is all types. |
2503 | -+pages+:: range selection of page address for PA (Page) records, e.g., “1,2,13-16” to include pages, 1, 2, 13, 14, 15 or 16. |
2504 | -+maxkey+:: maximum display length of key values in the output. Default value is 42. |
2505 | -+maxvalue+:: maximum display length of values in the output. Default value is 42. |
2506 | -+path+:: journal file path. Default is the journal file path of the currently instantiated Persistit instance. |
2507 | -+-v+:: verbose format. If specified, causes PM (Page Map) and TM (TransactionMap) records to be be display all map elements. |
2508 | - |
2509 | - |
2510 | -Note that the journal on a busy system contains a large number of records, so entering the +journal+ command without constraining the address range or record types may result in extremely lengthy output. |
2511 | - |
2512 | -=== Command: +open+ |
2513 | - |
2514 | -Opens a Persistit database for analysis. This task can only be used to examine a copy of a Persistit database that is not currently in use by an application. It works by attempting to open the volume and journal files using a synthesized configuration. It finds a collection of journal files and volume files specified by the +datapath+, +journalpath+ and +volumepath+ arguments; from these it derives a set of properties that will allow it to examine those journals and volumes. By default all volumes are opened in read-only mode and cannot be changed by operations executed from the command-line interface. |
2515 | - |
2516 | -If there already is an open Persistit instance, this command detaches it. For example, if you start +cliserver+ from a live Persistit instance and then issue the +open+ command, the live instance will continue to operate but +cliserver+ will no longer be attached to it. |
2517 | - |
2518 | -Note that you cannot +open+ volumes that are already open in a running Persistit instance due to their file locks. However, you can copy open volumes and journal files to another location and +open+ the copy. This is the primary use case for the +open+ command: to analyze a copy of a database (for example a copy recovered from backup) without having to a launch the application software that embeds Persistit. |
2519 | - |
2520 | -Arguments: |
2521 | - |
2522 | -[horizontal] |
2523 | -+datapath+:: a directory path for volume and journal files to be analyzed |
2524 | -+volumepath+:: overrides +datapath+ to specify an alternative location for volume files. |
2525 | -+journalpath+:: overrides +datapath+ to specify an alternative location for journal files. |
2526 | -+rmiport+:: specifies an RMI port to which an instance of the AdminUI can attach. |
2527 | -+-g+:: launch a local copy of AdminUI |
2528 | -+-y+:: attempt to recover committed transactions . |
2529 | - |
2530 | -Note that even if you specify +-y+ to recover transactions, the volume files will not be modified. But the +open+ command will add a new journal file containing modifications caused by the recovery process. You can simply delete that file when done. |
2531 | - |
2532 | -=== Command: +close+ |
2533 | - |
2534 | -Detach and close the current Persistit instance. If the CLI was started with a live Persistit instance then this command merely detaches from it; if the instance was created with the +open+ command then +close+ closes it and releases all related file locks, buffers, etc. |
2535 | - |
2536 | -=== Command: +source+ |
2537 | - |
2538 | -Execute command lines from a specified text file. Argument: |
2539 | - |
2540 | -[horizontal] |
2541 | -+file+:: file name of command input file |
2542 | |
2543 | === added file 'doc/Miscellaneous.rst' |
2544 | --- doc/Miscellaneous.rst 1970-01-01 00:00:00 +0000 |
2545 | +++ doc/Miscellaneous.rst 2012-05-30 18:23:19 +0000 |
2546 | @@ -0,0 +1,36 @@ |
2547 | +.. _Miscellaneous: |
2548 | + |
2549 | +Miscellaneous Topics |
2550 | +==================== |
2551 | + |
2552 | +Following are some short items you may find useful as you explore Akiban Persistit. Follow links to the API documentation for more details. |
2553 | + |
2554 | +Histograms |
2555 | +---------- |
2556 | + |
2557 | +The method ``com.persistit.Exchange#computeHistogram`` class provides a way to sample and summarize a set of keys in a ``Tree``. It works by traversing keys in index pages near the root of the tree. Because only a small fraction of all the keys in the tree are represented in the index, this can result in relatively small sample set of keys relatively quickly. The result can be used to estimate the actual number of keys. |
2558 | + |
2559 | +Temporary Volumes |
2560 | +----------------- |
2561 | + |
2562 | +A Persistit temporary volume is a special kind of Volume that is deleted when Persistit is closed. The update mechanism for temporary volumes avoids writing to disk whenever possible, and its contents are not recoverable Persistit shuts down. Therefore in some cases database operations on temporary volumes are faster. |
2563 | + |
2564 | +The primary use case for a temporary volume is an application that needs the unlimited size, but not the persistence of normal Persistit volumes. |
2565 | + |
2566 | +See the ``com.persistit.Persistit#createTemporaryVolume`` method for additional details. |
2567 | + |
2568 | +Logging |
2569 | +------- |
2570 | + |
2571 | +By default Persistit emits log messages to a file called persistit.log and also writes high level log messages to System.out. You can change this behavior by plugging in a different logging implementation. In particular, Persistit provides pluggable adapters for various other logging implementations, including Log4J, SLF4J, and the Java logging API introduced in JDK 1.4. For details see the API documentation for com.persistit.logging.AbstractPersistitLogger. |
2572 | + |
2573 | +Using one of these logging frameworks is simple. For example, the following code connects Persistit to an application-supplied SLF4J logger: |
2574 | + |
2575 | +.. code-block:: java |
2576 | + |
2577 | + db.setPersistitLogger(new Slf4jAdapter(LOG)) |
2578 | + |
2579 | +where ``db`` is the Persistit instance and ``LOG`` is a Logger supplied by SLF4J. This method should be called before the ``initialize`` method. |
2580 | + |
2581 | + |
2582 | + |
2583 | |
2584 | === removed file 'doc/Miscellaneous.txt' |
2585 | --- doc/Miscellaneous.txt 2012-04-30 22:09:31 +0000 |
2586 | +++ doc/Miscellaneous.txt 1970-01-01 00:00:00 +0000 |
2587 | @@ -1,32 +0,0 @@ |
2588 | -[[Miscellaneous]] |
2589 | -= Miscellaneous Topics |
2590 | - |
2591 | -Following are some short items you may find useful as you explore Akiban Persistit. Follow links to the API documentation for more details. |
2592 | - |
2593 | -== Histograms |
2594 | - |
2595 | -The method +com.persistit.Exchange#computeHistogram+ class provides a way to sample and summarize a set of keys in a +Tree+. It works by traversing keys in index pages near the root of the tree. Because only a small fraction of all the keys in the tree are represented in the index, this can result in relatively small sample set of keys relatively quickly. The result can be used to estimate the actual number of keys. |
2596 | - |
2597 | -== Temporary Volumes |
2598 | - |
2599 | -A Persistit temporary volume is a special kind of Volume that is deleted when Persistit is closed. The update mechanism for temporary volumes avoids writing to disk whenever possible, and its contents are not recoverable Persistit shuts down. Therefore in some cases database operations on temporary volumes are faster. |
2600 | - |
2601 | -The primary use case for a temporary volume is an application that needs the unlimited size, but not the persistence of normal Persistit volumes. |
2602 | - |
2603 | -See the +com.persistit.Persistit#createTemporaryVolume+ method for additional details. |
2604 | - |
2605 | -== Logging |
2606 | - |
2607 | -By default Persistit emits log messages to a file called persistit.log and also writes high level log messages to System.out. You can change this behavior by plugging in a different logging implementation. In particular, Persistit provides pluggable adapters for various other logging implementations, including Log4J, SLF4J, and the Java logging API introduced in JDK 1.4. For details see the API documentation for com.persistit.logging.AbstractPersistitLogger. |
2608 | - |
2609 | -Using one of these logging frameworks is simple. For example, the following code connects Persistit to an application-supplied SLF4J logger: |
2610 | - |
2611 | -[source,java] |
2612 | ----- |
2613 | -db.setPersistitLogger(new Slf4jAdapter(LOG)) |
2614 | ----- |
2615 | - |
2616 | -where +db+ is the Persistit instance and +LOG+ is a Logger supplied by SLF4J. This method should be called before the +initialize+ method. |
2617 | - |
2618 | - |
2619 | - |
2620 | |
2621 | === added file 'doc/PhysicalStorage.rst' |
2622 | --- doc/PhysicalStorage.rst 1970-01-01 00:00:00 +0000 |
2623 | +++ doc/PhysicalStorage.rst 2012-05-30 18:23:19 +0000 |
2624 | @@ -0,0 +1,142 @@ |
2625 | +.. _PhysicalStorage: |
2626 | + |
2627 | +Physical B-Tree Representation |
2628 | +============================== |
2629 | + |
2630 | +This chapter describes the physical structures used to represent Akiban Persistit records on disk and in memory. |
2631 | + |
2632 | +Files |
2633 | +----- |
2634 | + |
2635 | +Following is a directory listing illustrating a working Persistit database:: |
2636 | + |
2637 | + -rw-r--r--. 1 demo demo 24G Feb 8 13:18 akiban_data |
2638 | + -rw-r--r--. 1 demo demo 48K Feb 8 13:19 akiban_system |
2639 | + -rw-r--r--. 1 demo demo 954M Feb 8 13:18 akiban_journal.000000000225 |
2640 | + -rw-r--r--. 1 demo demo 954M Feb 8 13:19 akiban_journal.000000000226 |
2641 | + -rw-r--r--. 1 demo demo 954M Feb 8 13:19 akiban_journal.000000000227 |
2642 | + -rw-r--r--. 1 demo demo 662M Feb 8 13:19 akiban_journal.000000000228 |
2643 | + |
2644 | +This database contains two *volume* files, ``akiban_data`` and ``akiban_system`` and four files that constitute part of the *journal*. As explained below, Persistit records are usually stored in a combination of volume and journal files. |
2645 | + |
2646 | +.. _Journal: |
2647 | + |
2648 | +The Journal |
2649 | +----------- |
2650 | + |
2651 | +The *journal* is a set of files containing variable length records. The journal is append-only. New records are written only at the end; existing records are never overwritten. The journal consists of a numbered series of files having a configurable maximum size. When a journal file becomes full Persistit closes it and begins a new file with the next counter value. The maximum size of a journal file is determined by a configuration property called its block size. The default block size value is 1,000,000,000 bytes which works well with today’s standard server hardware. |
2652 | + |
2653 | +Every record in the journal has a 64-bit integer *journal address*. The journal address denotes which file contains the record and the record’s offset within that file. Journal addresses start at zero in a new database instance and grow perpetually. footnote:[Even on a system executing 1 million transactions per second the address space is large enough to last for hundreds of years.] |
2654 | + |
2655 | +Persistit writes two major types of records to journal files. |
2656 | + |
2657 | +- For each committed update transaction, Persistit writes a record containing sufficient information to replay the transaction during recovery. For example, when Persistit stores a key/value pair during a transaction, it writes a record to the journal containing the key and value. |
2658 | +- Persistit also writes all updated page images to the journal. Some of these are eventually copied to volume files, as described below. This write/copy mechanism is critical to Persistit’s crash-recovery mechanism (see :ref:`Recovery`). |
2659 | + |
2660 | +As updates are applied, Persistit constantly appends new information- both transaction records and modified page images - to the end of the highest-numbered file. To prevent the aggregation of a large number of journal files Persistit also works to copy or remove information from older journal files so that they can be deleted. The background thread responsible for this activity is called the ``JOURNAL_COPIER`` thread. The JOURNAL_COPIER copies pages from the journal back into their home volume files, allowing old files to be deleted. Normally a Persistit system at rest gradually copies all update page images and perform checkpoints so that only one small journal file remains. Applications can accelerate that process by calling the ``com.persistit.Persistit#copyBackPages`` method. |
2661 | + |
2662 | +The journal is critical to ensuring Persistit can recover structurally intact B-Trees and apply all committed transactions after a system failure. For this reason, unless the JOURNAL_COPIER is entirely caught up, any attempt to save the state of a Persistit database must include both the volume and journal files. |
2663 | + |
2664 | +The journal also plays a critical role during concurrent backup. To back up a running Persistit database, the ``com.persistit.BackupTask`` does the following: |
2665 | + |
2666 | +- Enables ``appendOnly`` mode to suspend the copying of updated page images. |
2667 | +- Copies the appropriate volume and journal files |
2668 | +- Disables ``appendOnly`` mode to allow JOURNAL_COPIER to continue. |
2669 | + |
2670 | +For more details on the journal, checkpoints and transactions, see :ref:`Recovery`. For more information on concurrent backup and other management tasks, see :ref:`Management`. |
2671 | + |
2672 | +Pages and Volumes |
2673 | +----------------- |
2674 | + |
2675 | +Persistit ultimately stores its data in one or more Volume files. Persistit manages volume files internally in sections called pages. Every page within one volume has the same size. The page size is configurable and may be 1,024, 2,048, 4,096, 8,192, or 16,384 (recommended) bytes long. Once the page size for a volume has been established, it cannot be changed. See :ref:`Configuration` for details of how to assign the page size for a new volume. |
2676 | + |
2677 | +Directory Tree |
2678 | +^^^^^^^^^^^^^^ |
2679 | + |
2680 | +Within a volume there can be an unlimited number of B-Trees. (B-Trees are also called simply “trees” in this document.) A tree consists of a set of pages including a *root page*, *index pages* and *data pages*. The root page can be data page if the tree is trivial and contains only small number of records. Usually the root page is an index page which contains references to other index pages which in turn may refer to data pages. |
2681 | + |
2682 | +Persistit manages a potentially large number of trees by maintaining a tree of trees called ``_directory``. The ``_directory`` tree contains the name, root page address, ``com.persistit.Accumulator`` data and ``com.persistit.TreeStatistics`` data for all the other trees in the volume. The tree name ``_directory`` is reserved and may not be used when creating an Exchange. |
2683 | + |
2684 | +Data Pages |
2685 | +^^^^^^^^^^ |
2686 | + |
2687 | +A data page contains a representation of one or more variable-length key/value pairs. The number of key/value pairs depends on the page size, and the sizes of the serialized keys and values. The first key in each data page is stored in its entirety, while subsequent keys are stored with *prefix compression* to reduce storage footprint and accelerate searches. Therefore the storage size of the second and subsequent keys in a data page depend on how many of the leading bytes of its serialized form match its predecessor. (See :ref:`Key` and :ref:`Value` for information on how Persistit encodes logical Java values into the byte arrays stored in a data page.) |
2688 | + |
2689 | +Index Pages |
2690 | +^^^^^^^^^^^ |
2691 | + |
2692 | +An index page has a structure similar to a data page except that instead of holding serialized value data, it instead contains page addresses of subordinate pages within the tree. |
2693 | + |
2694 | +.. TODO - diagram of B-Tree, page layouts, etc |
2695 | + |
2696 | +.. _Recovery: |
2697 | + |
2698 | +Recovery |
2699 | +======== |
2700 | + |
2701 | +Akiban Persistit is designed, implemented and tested to ensure that whether the application shuts down gracefully or crashes without cleanly closing the database, the database remains structurally intact and internally consistent after restart. |
2702 | + |
2703 | +To do this, Persistit performs a process called *recovery* every time it starts up. The recovery process is generally very fast after a normal shutdown. However, it can take a considerable amount of time after a crash because many committed transactions may need to be executed. |
2704 | + |
2705 | +Recovery performs two major activities: |
2706 | + |
2707 | +- Restores all B-Trees to an internally consistent state with a known timestamp. |
2708 | +- Replays all transaction that committed after that timestamp. |
2709 | +- Prunes multi-version values belonging to certain aborted transactions (see :ref:`Pruning`). |
2710 | + |
2711 | +To accomplish this, Persistit writes all updates first to the :ref:`Journal`. Persistit also periodically writes *checkpoint* records to the journal. During recovery, Persistit finds the last valid checkpoint written before shutdown or crash, restores B-Trees to state consistent with that checkpoint, and then replays transactions that committed after the checkpoint. |
2712 | + |
2713 | +Recovery depends on the availability of the volume and journal files as they existed prior to abrupt termination. If these are modified or destroyed outside of Persistit, successful recovery is unlikely. |
2714 | + |
2715 | +Timestamps and Checkpoints |
2716 | +-------------------------- |
2717 | + |
2718 | +Persistit maintains a universal counter called the *timestamp* counter. Every update operation assigns a new, larger timestamp, and every record in the journal includes the timestamp assigned to the operation writing the record. The timestamp counter is unrelated to clock time. It is merely a counter. |
2719 | + |
2720 | +A *checkpoint* is simply a timestamp for which a valid recovery is possible. Periodically Persistit chooses a timestamp to be a new checkpoint. Over time it then ensures that all pages updated before the checkpoint have been written to the journal, and then writes a checkpoint marker. By default checkpoints occur once every two minutes. Normal shutdown through ``com.persistit.Persistit#close`` writes a final checkpoint to the journal regardless of when the last checkpoint cycle occurred. That final checkpoint is what allows recovery after a normal shutdown to be very fast. |
2721 | + |
2722 | +Upon start-up Persistit starts by finding the last valid checkpoint timestamp, and then recovers only those page images from the journal that were written prior to it. The result is that all B-Trees are internally consistent and contain all the updates that were issued and committed to disk before the checkpoint timestamp and none the occurred after the checkpoint timestamp. |
2723 | + |
2724 | +Then Persistit locates and reapplies all transaction records in the journal for transactions that committed after the last valid checkpoint timestamp. These transactions are reapplied to the database, with the result that: |
2725 | + |
2726 | +- The B-Tree index and data structures are intact. All store, fetch, remove and traverse operations will complete successfully. footnote:[Persistit provides the utility class com.persistit.IntegrityCheck to verify the integrity of a Volume.] |
2727 | +- All committed transactions are present in the recovered database. (See :ref:`Transactions` for durability determined by ``CommitPolicy``.) |
2728 | + |
2729 | +For updates occurring outside of a transaction the resulting state is identical to some consistent, reasonably recent state prior to the termination. (“Reasonably recent” depends on the checkpoint interval, which by default is set to two minutes.) |
2730 | + |
2731 | +Flush/Force/Checkpoint |
2732 | +^^^^^^^^^^^^^^^^^^^^^^ |
2733 | + |
2734 | +An application may require certainty at various points that all pending updates have been fully written to disk. The ``com.persistit.Persistit`` class provides three methods to ensure that updates have been written: |
2735 | + |
2736 | + ``com.persistit.Persistit#flush`` |
2737 | + causes Persistit to write all pending updates to the journal. Upon successful completion of flush any pages that needed writing prior to the call to flush are |
2738 | + guaranteed to have been written to their respective volume files. |
2739 | + ``com.persistit.Persistit#force`` |
2740 | + forces the underlying operating system to write pending updates from the operating system’s write-behind cache to the actual disk. (This operation relies on |
2741 | + the underlying ``java.io.Filechannel#force(boolean)`` method.) |
2742 | + ``com.persistit.Persistit#checkpoint`` |
2743 | + causes Persistit to allocate a new checkpoint timestamp and then wait for all updates that happened before that timestamp to be committed to disk. |
2744 | + |
2745 | +However, typical applications, especially those using :ref:`Transactions`, do not need to invoke these methods. Once a Transaction is durable, so are all other transactions that occurred at timestamps earlier than the transaction’s commit timestamp and no other method calls are required. |
2746 | + |
2747 | + |
2748 | +The Buffer Pool |
2749 | +--------------- |
2750 | + |
2751 | +Persistit maintains a cache of page copies in memory called the *buffer pool*. The buffer pool is a critical resource in reducing disk I/O and providing good run-time performance. After performing a relatively expensive disk operation to read a copy of a page into the buffer pool, Persistit retains that copy to allow potentially many fetch and update operations to be performed against keys and values stored in that page. |
2752 | + |
2753 | +Persistit optimizes update operations by writing updated database pages lazily, generally a few seconds to minutes after the update has been performed on the in-memory copy of the page cached in the buffer pool. By writing lazily, Persistit allows many update operations to be completed on each page before incurring a relatively expensive disk I/O operation to write the updated version of the page to the Volume. |
2754 | + |
2755 | +In Persistit the buffer pool is a collection of buffers allocated from the heap for the duration of Persistit’s operation. The buffers are allocated by the ``com.persistit.Persistit#initialize`` method and are released when the application invokes close. Because buffers are allocated for the life of the Persistit instance, they impose no garbage collection overhead. (However, especially when using large buffer pool allocation in a JVM with a large heap, there are some special memory configuration issues to consider. See :ref:`Configuration` for details.) |
2756 | + |
2757 | +Persistit allocates buffers from the buffer pool in approximately least-recently-used (LRU) order. Most applications exhibit behavior in which data, having been accessed once, is read or updated several more times before the application moves to a different area of the database (locality of reference). LRU is an allocation strategy the yields reasonably good overall throughput by maintaining pages that are likely to be used again in the buffer pool in preference to pages that have not been used for a relatively long time. |
2758 | + |
2759 | +Generally, allocating more buffers in the buffer pool increases the likelihood that a page will be found in the pool rather than having to be reloaded from disk. Since disk I/O is relatively expensive, this means that enlarging the buffer pool is a good strategy for reducing disk I/O and thereby increasing throughput. Persistit is designed to manage extremely large buffer pools very efficiently, so if memory is available, it is generally a good strategy to maximum buffer pool size. |
2760 | + |
2761 | +Tools |
2762 | +----- |
2763 | + |
2764 | +The command-line interface (see :ref:`CLI`) includes tools you can use to examine pages in volumes and records in the journal. Two of these include the ``jview`` and ``pview`` tasks. The ``jview`` command displays journal records selected within an address range, by type, by page address, and using other selection criteria in a readable form. The ``pview`` command displays the contents of pages selected by page address or key from a volume, or by journal address from the journal. |
2765 | + |
2766 | + |
2767 | |
2768 | === removed file 'doc/PhysicalStorage.txt' |
2769 | --- doc/PhysicalStorage.txt 2012-05-04 13:33:49 +0000 |
2770 | +++ doc/PhysicalStorage.txt 1970-01-01 00:00:00 +0000 |
2771 | @@ -1,126 +0,0 @@ |
2772 | -[[PhysicalStorage]] |
2773 | -= Physical B-Tree Representation |
2774 | - |
2775 | -This chapter describes the physical structures used to represent Akiban Persistit records on disk and in memory. |
2776 | - |
2777 | -== Files |
2778 | - |
2779 | -Following is a directory listing illustrating a working Persistit database: |
2780 | - |
2781 | ----- |
2782 | --rw-r--r--. 1 demo demo 24G Feb 8 13:18 akiban_data |
2783 | --rw-r--r--. 1 demo demo 48K Feb 8 13:19 akiban_system |
2784 | --rw-r--r--. 1 demo demo 954M Feb 8 13:18 akiban_journal.000000000225 |
2785 | --rw-r--r--. 1 demo demo 954M Feb 8 13:19 akiban_journal.000000000226 |
2786 | --rw-r--r--. 1 demo demo 954M Feb 8 13:19 akiban_journal.000000000227 |
2787 | --rw-r--r--. 1 demo demo 662M Feb 8 13:19 akiban_journal.000000000228 |
2788 | ----- |
2789 | - |
2790 | -This database contains two _volume_ files, +akiban_data+ and +akiban_system+ and four files that constitute part of the _journal_. As explained below, Persistit records are usually stored in a combination of volume and journal files. |
2791 | - |
2792 | -[[Journal]] |
2793 | -== The Journal |
2794 | - |
2795 | -The _journal_ is a set of files containing variable length records. The journal is append-only. New records are written only at the end; existing records are never overwritten. The journal consists of a numbered series of files having a configurable maximum size. When a journal file becomes full Persistit closes it and begins a new file with the next counter value. The maximum size of a journal file is determined by a configuration property called its block size. The default block size value is 1,000,000,000 bytes which works well with today’s standard server hardware. |
2796 | - |
2797 | -Every record in the journal has a 64-bit integer _journal address_. The journal address denotes which file contains the record and the record’s offset within that file. Journal addresses start at zero in a new database instance and grow perpetually. footnote:[Even on a system executing 1 million transactions per second the address space is large enough to last for hundreds of years.] |
2798 | - |
2799 | -Persistit writes two major types of records to journal files. |
2800 | - |
2801 | -- For each committed update transaction, Persistit writes a record containing sufficient information to replay the transaction during recovery. For example, when Persistit stores a key/value pair during a transaction, it writes a record to the journal containing the key and value. |
2802 | -- Persistit also writes all updated page images to the journal. Some of these are eventually copied to volume files, as described below. This write/copy mechanism is critical to Persistit’s crash-recovery mechanism (see <<Recovery>>). |
2803 | - |
2804 | -As updates are applied, Persistit constantly appends new information- both transaction records and modified page images - to the end of the highest-numbered file. To prevent the aggregation of a large number of journal files Persistit also works to copy or remove information from older journal files so that they can be deleted. The background thread responsible for this activity is called the +JOURNAL_COPIER+ thread. The JOURNAL_COPIER copies pages from the journal back into their home volume files, allowing old files to be deleted. Normally a Persistit system at rest gradually copies all update page images and perform checkpoints so that only one small journal file remains. Applications can accelerate that process by calling the +com.persistit.Persistit#copyBackPages+ method. |
2805 | - |
2806 | -The journal is critical to ensuring Persistit can recover structurally intact B-Trees and apply all committed transactions after a system failure. For this reason, unless the JOURNAL_COPIER is entirely caught up, any attempt to save the state of a Persistit database must include both the volume and journal files. |
2807 | - |
2808 | -The journal also plays a critical role during concurrent backup. To back up a running Persistit database, the +com.persistit.BackupTask+ does the following: |
2809 | - |
2810 | -- Enables +appendOnly+ mode to suspend the copying of updated page images. |
2811 | -- Copies the appropriate volume and journal files |
2812 | -- Disables +appendOnly+ mode to allow JOURNAL_COPIER to continue. |
2813 | - |
2814 | -For more details on the journal, checkpoints and transactions, see <<Recovery>>. For more information on concurrent backup and other management tasks, see <<Management>>. |
2815 | - |
2816 | -== Pages and Volumes |
2817 | - |
2818 | -Persistit ultimately stores its data in one or more Volume files. Persistit manages volume files internally in sections called pages. Every page within one volume has the same size. The page size is configurable and may be 1,024, 2,048, 4,096, 8,192, or 16,384 (recommended) bytes long. Once the page size for a volume has been established, it cannot be changed. See <<Configuration>> for details of how to assign the page size for a new volume. |
2819 | - |
2820 | -=== Directory Tree |
2821 | - |
2822 | -Within a volume there can be an unlimited number of B-Trees. (B-Trees are also called simply “trees” in this document.) A tree consists of a set of pages including a _root page_, _index pages_ and _data pages_. The root page can be data page if the tree is trivial and contains only small number of records. Usually the root page is an index page which contains references to other index pages which in turn may refer to data pages. |
2823 | - |
2824 | -Persistit manages a potentially large number of trees by maintaining a tree of trees called +_directory+. The +_directory+ tree contains the name, root page address, +com.persistit.Accumulator+ data and +com.persistit.TreeStatistics+ data for all the other trees in the volume. The tree name +_directory+ is reserved and may not be used when creating an Exchange. |
2825 | - |
2826 | -=== Data Pages |
2827 | - |
2828 | -A data page contains a representation of one or more variable-length key/value pairs. The number of key/value pairs depends on the page size, and the sizes of the serialized keys and values. The first key in each data page is stored in its entirety, while subsequent keys are stored with _prefix compression_ to reduce storage footprint and accelerate searches. Therefore the storage size of the second and subsequent keys in a data page depend on how many of the leading bytes of its serialized form match its predecessor. (See <<Key>> and <<Value>> for information on how Persistit encodes logical Java values into the byte arrays stored in a data page.) |
2829 | - |
2830 | -=== Index Pages |
2831 | - |
2832 | -An index page has a structure similar to a data page except that instead of holding serialized value data, it instead contains page addresses of subordinate pages within the tree. |
2833 | - |
2834 | -**** |
2835 | -TODO - diagram of B-Tree, page layouts, etc |
2836 | -**** |
2837 | -[[Recovery]] |
2838 | -== Recovery |
2839 | - |
2840 | -Akiban Persistit is designed, implemented and tested to ensure that whether the application shuts down gracefully or crashes without cleanly closing the database, the database remains structurally intact and internally consistent after restart. |
2841 | - |
2842 | -To do this, Persistit performs a process called _recovery_ every time it starts up. The recovery process is generally very fast after a normal shutdown. However, it can take a considerable amount of time after a crash because many committed transactions may need to be executed. |
2843 | - |
2844 | -Recovery performs two major activities: |
2845 | - |
2846 | -- Restores all B-Trees to an internally consistent state with a known timestamp. |
2847 | -- Replays all transaction that committed after that timestamp. |
2848 | -- Prunes multi-version values belonging to certain aborted transactions (see <<Pruning>>). |
2849 | - |
2850 | -To accomplish this, Persistit writes all updates first to the <<Journal>>. Persistit also periodically writes _checkpoint_ records to the journal. During recovery, Persistit finds the last valid checkpoint written before shutdown or crash, restores B-Trees to state consistent with that checkpoint, and then replays transactions that committed after the checkpoint. |
2851 | - |
2852 | -Recovery depends on the availability of the volume and journal files as they existed prior to abrupt termination. If these are modified or destroyed outside of Persistit, successful recovery is unlikely. |
2853 | - |
2854 | -=== Timestamps and Checkpoints |
2855 | - |
2856 | -Persistit maintains a universal counter called the _timestamp_ counter. Every update operation assigns a new, larger timestamp, and every record in the journal includes the timestamp assigned to the operation writing the record. The timestamp counter is unrelated to clock time. It is merely a counter. |
2857 | - |
2858 | -A _checkpoint_ is simply a timestamp for which a valid recovery is possible. Periodically Persistit chooses a timestamp to be a new checkpoint. Over time it then ensures that all pages updated before the checkpoint have been written to the journal, and then writes a checkpoint marker. By default checkpoints occur once every two minutes. Normal shutdown through +com.persistit.Persistit#close+ writes a final checkpoint to the journal regardless of when the last checkpoint cycle occurred. That final checkpoint is what allows recovery after a normal shutdown to be very fast. |
2859 | - |
2860 | -Upon start-up Persistit starts by finding the last valid checkpoint timestamp, and then recovers only those page images from the journal that were written prior to it. The result is that all B-Trees are internally consistent and contain all the updates that were issued and committed to disk before the checkpoint timestamp and none the occurred after the checkpoint timestamp. |
2861 | - |
2862 | -Then Persistit locates and reapplies all transaction records in the journal for transactions that committed after the last valid checkpoint timestamp. These transactions are reapplied to the database, with the result that: |
2863 | - |
2864 | -- The B-Tree index and data structures are intact. All store, fetch, remove and traverse operations will complete successfully. footnote:[Persistit provides the utility class com.persistit.IntegrityCheck to verify the integrity of a Volume.] |
2865 | -- All committed transactions are present in the recovered database. (See <<Transactions>> for durability determined by +CommitPolicy+.) |
2866 | - |
2867 | -For updates occurring outside of a transaction the resulting state is identical to some consistent, reasonably recent state prior to the termination. (“Reasonably recent” depends on the checkpoint interval, which by default is set to two minutes.) |
2868 | - |
2869 | -=== Flush/Force/Checkpoint |
2870 | - |
2871 | -An application may require certainty at various points that all pending updates have been fully written to disk. The +com.persistit.Persistit+ class provides three methods to ensure that updates have been written: |
2872 | - |
2873 | -[horizontal] |
2874 | -+com.persistit.Persistit#flush+:: causes Persistit to write all pending updates to the journal. Upon successful completion of flush any pages that needed writing prior to the call to flush are guaranteed to have been written to their respective volume files. |
2875 | -+com.persistit.Persistit#force+:: forces the underlying operating system to write pending updates from the operating system’s write-behind cache to the actual disk. (This operation relies on the underlying +java.io.Filechannel#force(boolean)+ method.) |
2876 | -+com.persistit.Persistit#checkpoint+:: causes Persistit to allocate a new checkpoint timestamp and then wait for all updates that happened before that timestamp to be committed to disk. |
2877 | - |
2878 | -However, typical applications, especially those using <<Transactions>>, do not need to invoke these methods. Once a Transaction is durable, so are all other transactions that occurred at timestamps earlier than the transaction’s commit timestamp and no other method calls are required. |
2879 | - |
2880 | - |
2881 | -== The Buffer Pool |
2882 | - |
2883 | -Persistit maintains a cache of page copies in memory called the _buffer pool_. The buffer pool is a critical resource in reducing disk I/O and providing good run-time performance. After performing a relatively expensive disk operation to read a copy of a page into the buffer pool, Persistit retains that copy to allow potentially many fetch and update operations to be performed against keys and values stored in that page. |
2884 | - |
2885 | -Persistit optimizes update operations by writing updated database pages lazily, generally a few seconds to minutes after the update has been performed on the in-memory copy of the page cached in the buffer pool. By writing lazily, Persistit allows many update operations to be completed on each page before incurring a relatively expensive disk I/O operation to write the updated version of the page to the Volume. |
2886 | - |
2887 | -In Persistit the buffer pool is a collection of buffers allocated from the heap for the duration of Persistit’s operation. The buffers are allocated by the +com.persistit.Persistit#initialize+ method and are released when the application invokes close. Because buffers are allocated for the life of the Persistit instance, they impose no garbage collection overhead. (However, especially when using large buffer pool allocation in a JVM with a large heap, there are some special memory configuration issues to consider. See <<Configuration>> for details.) |
2888 | - |
2889 | -Persistit allocates buffers from the buffer pool in approximately least-recently-used (LRU) order. Most applications exhibit behavior in which data, having been accessed once, is read or updated several more times before the application moves to a different area of the database (locality of reference). LRU is an allocation strategy the yields reasonably good overall throughput by maintaining pages that are likely to be used again in the buffer pool in preference to pages that have not been used for a relatively long time. |
2890 | - |
2891 | -Generally, allocating more buffers in the buffer pool increases the likelihood that a page will be found in the pool rather than having to be reloaded from disk. Since disk I/O is relatively expensive, this means that enlarging the buffer pool is a good strategy for reducing disk I/O and thereby increasing throughput. Persistit is designed to manage extremely large buffer pools very efficiently, so if memory is available, it is generally a good strategy to maximum buffer pool size. |
2892 | - |
2893 | -== Tools |
2894 | - |
2895 | -The command-line interface (see <<CLI>>) includes tools you can use to examine pages in volumes and records in the journal. Two of these include the +jview+ and +pview+ tasks. The +jview+ command displays journal records selected within an address range, by type, by page address, and using other selection criteria in a readable form. The +pview+ command displays the contents of pages selected by page address or key from a volume, or by journal address from the journal. |
2896 | - |
2897 | - |
2898 | |
2899 | === added file 'doc/ReleaseNotes.rst' |
2900 | --- doc/ReleaseNotes.rst 1970-01-01 00:00:00 +0000 |
2901 | +++ doc/ReleaseNotes.rst 2012-05-30 18:23:19 +0000 |
2902 | @@ -0,0 +1,84 @@ |
2903 | +************************************ |
2904 | +Akiban-Persistit 3.1.1 Release Notes |
2905 | +************************************ |
2906 | + |
2907 | +Release Date |
2908 | +============ |
2909 | +May 25, 2012 |
2910 | + |
2911 | +Overview |
2912 | +======== |
2913 | +This is the first open source release of the Persistit project (https://launchpad.net/akiban-persistit). |
2914 | + |
2915 | +See http://www.akiban.com/akiban-persistit for a summary of features and benefits, licensing information and how to get support. |
2916 | + |
2917 | +Documentation |
2918 | +============= |
2919 | +Users Guide (http://www.akiban.com/ak-docs/admin/persistit) |
2920 | +JavaDoc (http://www.akiban.com/ak-docs/admin/persistit/apidocs) |
2921 | + |
2922 | +Building Akiban-Persistit |
2923 | +========================= |
2924 | +Use Maven (maven.apache.org) to build Persistit. |
2925 | + |
2926 | +To build:: |
2927 | + |
2928 | + mvn install |
2929 | + |
2930 | +The resulting jar files are in the ``target`` directory. To build the Javadoc:: |
2931 | + |
2932 | + mvn javadoc:javadoc |
2933 | + |
2934 | +The resulting Javadoc HTML files are in ``target/site/apidocs``. |
2935 | + |
2936 | +Building and Running the Examples |
2937 | +--------------------------------- |
2938 | + |
2939 | +Small examples are located in the ``examples`` directory. Each has a short README file describing the example, and an Ant build script (http://ant.apache.org). After building the main akiban-persisit jar file using Maven, you may run:: |
2940 | + |
2941 | + ant run |
2942 | + |
2943 | +in each of the examples subdirectories to build and run the examples. |
2944 | + |
2945 | +Known Issues |
2946 | +============ |
2947 | + |
2948 | +Transactional Tree Management |
2949 | +----------------------------- |
2950 | + |
2951 | +All operations within Trees such as store, fetch, remove and traverse are correctly supported within transactions. However, the operations to create and delete Tree instances currently do not respect transaction boundaries. For example, if a transaction creates a new Tree, it is immediately visible within other Transactions and will continue to exist even if the original transaction aborts. (However, records inserted or modified by the original transaction will not be visible until the transaction commits.) Prior to creating/removing trees, transaction processing should be quiesced and allowed to complete. |
2952 | + |
2953 | +Problems with Disk Full - Bug 916071 |
2954 | +------------------------------------ |
2955 | + |
2956 | +There are rare cases where Persistit will generate exceptions other than java.io.IOException: No space left on device when a disk volume containing the journal or volume file fills up. The database will be intact upon recovery, but the application may receive unexpected exceptions. |
2957 | + |
2958 | +Out of Memory Error, Direct Memory Buffer - Bug 985117 |
2959 | +------------------------------------------------------ |
2960 | + |
2961 | +Out of Memory Error, Direct Memory Buffer. Can cause failed transactions under extreme load conditions as a result of threads getting backed up writing to the journal file. However, this error is transient and recoverable by by retrying the failed transaction. |
2962 | + |
2963 | +* Workaround: Ensure your application has the ability to retry failed transactions |
2964 | + |
2965 | + |
2966 | +Tree#getChangeCount may return inaccurate result - Bug 986465 |
2967 | +------------------------------------------------------------- |
2968 | + |
2969 | +The getChangeCount method may return inaccurate results as its not currently transactional. The primary consumer is the PersistitMap. As a result of this bug Persistit may not generate java.util.ConcurrentModiciationException when it is supposed to. |
2970 | + |
2971 | +Multi-Version-Values sometimes not fully pruned - Bug 1000331 |
2972 | +------------------------------------------------------------- |
2973 | + |
2974 | +Multi-version values are not always pruned properly causing volume growth. The number of MVV records and their overhead size can be obtaining by running the IntegrityCheck task. |
2975 | + |
2976 | +* Workaround 1: Run the IntegrityCheck task (CLI command icheck) with the -P option which will prune the MVVs. This will remove obsolete MVV instances and in many cases free up pages in which new data can be stored. However, it will not reduce the actual size of the volume file. |
2977 | + |
2978 | +* Workaround 2: To reduce the size of the volume you can use the CLI commands save and load to offload and then reload the data into a newly created volume file. See http://www.akiban.com/ak-docs/admin/persistit/Management.html#management for more information about these operations. |
2979 | + |
2980 | + |
2981 | +Buffer Pool Configuration |
2982 | +========================= |
2983 | +For optimal performance, proper configuration of the Persistit buffer pool is required. See section "Configuring the Buffer Pool" in the configuration document http://www.akiban.com/ak-docs/admin/persistit/Configuration.html |
2984 | + |
2985 | +.. note:: Especially when used with multi-gigabyte heaps, the default Hotspot JVM server heuristics are be suboptimal for Persistit applications. Persistit is usually configured to allocate a large fraction of the heap to Buffer instances that are allocated at startup and held for the duration of the Persistit instance. For efficient operation, all of the Buffer instances must fit in the tenured (old) generation of the heap to avoid very significant garbage collector overhead. Use either -XX:NewSize or -Xmn to adjust the relative sizes of the new and old generations. |
2986 | + |
2987 | |
2988 | === added file 'doc/Security.rst' |
2989 | --- doc/Security.rst 1970-01-01 00:00:00 +0000 |
2990 | +++ doc/Security.rst 2012-05-30 18:23:19 +0000 |
2991 | @@ -0,0 +1,93 @@ |
2992 | +.. _Security: |
2993 | + |
2994 | +Security Notes |
2995 | +============== |
2996 | + |
2997 | +Akiban Persistit provides no built-in data access control because it is intended for embedded use in applications that provide their own logical access control. Security-conscious applications must also prevent unauthorized access to Persistit's physical files and to the Persistit API. The following resources must be protected from unauthorized access: |
2998 | + |
2999 | +- Persistit volume files |
3000 | +- configuration properties file, if one is used |
3001 | +- access by unauthorized code to the API exposed by the Persistit library |
3002 | +- the port opened and exposed by Persistit when either the ``com.persistit.rmiport`` or ``com.persistit.rmihost`` property is set. If you are using Persistit's remote administration feature, be sure to block unauthorized access to the RMI port. |
3003 | +- the :ref:`cliserver` if instantiated |
3004 | + |
3005 | +In addition to these general deployment considerations, Persistit requires certain permissions in an environment controlled by a security manager. |
3006 | + |
3007 | +Java programs run from the command line typically do not install a security manager, and therefore implicitly grant all permissions. However, when Persistit is used within an Applet, or within any framework that installs a security manager, it is important to understand what permissions are required. |
3008 | + |
3009 | +Security Domains |
3010 | +---------------- |
3011 | + |
3012 | +This section assumes a basic understanding of the Java security model. See http://download.oracle.com/javase/1.5.0/docs/guide/security/spec/security-spec.doc2.html[New Protection Mechanisms - Overview of Basic Concepts] for further information. |
3013 | + |
3014 | +Note that when Java is started from the command line, as is often the case in server applications, all security privileges are granted by default. The information in this section is intended for cases where security privileges need to be controlled. |
3015 | + |
3016 | +Akiban Persistit performs various security-sensitive operations: it reads and writes files, it reads system properties, it optionally opens a TCP/IP socket, and it performs various security-sensitive operations related to reflection and serialization. These operations are divided into two categories: those required only by the Persistit library itself, and those required by the application that is using Persistit. For example, the application code must have permission to read and write files, but it does not require permission to access private fields through reflection; only the Persistit library itself needs this permission. The latter operation is called a “privileged” operation because Persistit invokes the access controller's doPrivileged method to establish its permission to perform the privileged operation. |
3017 | + |
3018 | +At a practical level, this means you can create two separate security domains for applications embedding Persistit. One domain is specific to the Persistit library itself, and grants all the permissions required by Persistit, including the privileged permissions. The other domain includes the application, and grants only the non-privileged permissions. |
3019 | + |
3020 | +Using the default java.lang.SecurityManager implementation, you define domains and the permissions available to them in a policy file stored in the user's home directory. For those already familiar with the policy file format, here is a security policy file that illustrates these concepts: |
3021 | + |
3022 | +.. code-block:: java |
3023 | + |
3024 | + grant codeBase "file:/appdir/myapplication.jar" { |
3025 | + permission java.io.FilePermission "e:\\data\\*", "read, write, delete"; |
3026 | + permission java.io.FilePermission "e:\\logs\\*", "read, write, delete"; |
3027 | + permission java.net.SocketPermission "localhost", |
3028 | + "accept, connect, listen, resolve"; |
3029 | + }; |
3030 | + |
3031 | + grant codeBase "file:/lib/akiban-persistit.jar" { |
3032 | + permission java.io.FilePermission "<<ALL FILES>>", "read, write, delete"; |
3033 | + permission java.net.SocketPermission "*:1099-", |
3034 | + "accept, connect, listen, resolve"; |
3035 | + permission java.lang.reflect.ReflectPermission "suppressAccessChecks"; |
3036 | + permission java.io.SerializablePermission "enableSubclassImplementation"; |
3037 | + permission java.util.PropertyPermission "com.persistit.*", "read"; |
3038 | + permission java.lang.RuntimePermission "accessDeclaredMembers"; |
3039 | + }; |
3040 | + |
3041 | +This policy file sets up two security domains. One covers the application code in ``myapplication.jar`` and grants just the restricted set of permissions needed by the application, while the other grants additional permissions to the Persistit library. |
3042 | + |
3043 | +Although the file and socket permissions granted by the privileged domain are less restrictive than those granted to ``myapplication.jar``, the actual permission granted to running code is the intersection of these two and is therefore restricted to just the set of files and sockets granted to myapplication.jar. |
3044 | + |
3045 | +Permissions Required for DefaultValueCoder |
3046 | +------------------------------------------ |
3047 | + |
3048 | +DefaultValueCoder performs three security-sensitive operations: |
3049 | + |
3050 | +- It enumerates the declared fields of the class being serialized, |
3051 | +- It reads and writes data from and to those fields using reflection even if they are private, and |
3052 | +- It overrides the default implementations of java.io.ObjectInputStream and java.io.ObjectOutputStream. |
3053 | + |
3054 | +If a SecurityManager is installed then three permissions must be granted to enable this new mechanism:: |
3055 | + |
3056 | + java.lang.RuntimePermission "accessDeclaredMembers"; |
3057 | + java.lang.reflect.ReflectPermission("suppressAccessChecks") |
3058 | + java.io.SerializablePermission("enableSubclassImplementation") |
3059 | + |
3060 | +Persistit acquires these permissions through privileged operations, meaning that only the Persistit library domain needs to have them – they do not need to be and should not be granted to the application domain. |
3061 | + |
3062 | +Permission Required for Reading System Properties |
3063 | +------------------------------------------------- |
3064 | + |
3065 | +Persistit attempts to read system properties whose names begin with “com.persistit.” Specific permission to do this is granted by the line:: |
3066 | + |
3067 | + permission java.util.PropertyPermission "com.persistit.*", "read"; |
3068 | + |
3069 | +Again, only the Persistit library domain needs to have this permission. If this permission is not granted, Persistit ignores all system properties. |
3070 | + |
3071 | +Permissions Required for File and Socket I/O |
3072 | +-------------------------------------------- |
3073 | + |
3074 | +Persistit needs permission to read and write its volume and journal files, to read a configuration properties file and (optionally) write to a log file. File I/O permissions also apply to the source and destination files specified for Import and Export tasks available within the AdminUI utility. In addition, if you specify either the rmihost or rmiport property to enable remote administration, Persistit needs permission to create RMI connections. |
3075 | + |
3076 | +These are not privileged operations, meaning that if the policy establishes separate domains for the application and the Persistit library, both domains must grant permission for all I/O operations. (If they were privileged operations, an untrusted application code could use the Persistit library as a proxy to perform malicious file I/O.) As is defined by the Java security mechanism, when Persistit attempts to open a file, permissions of both the application domain and the Persistit library domains are checked; if the operation is denied by either domain then the attempt fails with a java.security.AccessControlException. |
3077 | + |
3078 | +As specified in the sample policy file above, the Persistit library domain has been granted permissions on `<<ALL FILES>>`. This means that the application domain controls what subset of the file system is accessible. In the example, files may only be read and written to the e:\data and e:\logs directories on a Windows box. (See the Java documentation on Permissions for details on how to construct File and Socket permissions.) |
3079 | + |
3080 | +Deploying Persistit as an Installed Optional Package |
3081 | +---------------------------------------------------- |
3082 | + |
3083 | +A convenient way to grant Persistit the permissions required to perform its privileged operations is to install it as an optional package. The Sun Java Runtime Environment treats JAR files located in the <jre-home>/lib/ext directory as optional Java extension classes, and by default grants them the same privileges as Java system classes. If the Persistit library is loaded from this directory then only the application File and Socket privileges need to be granted explicitly through a security policy. To deploy Persistit in this manner simply copy the Persistit library jar file to the appropriate ``*jre-home*/lib/ext`` directory. |
3084 | + |
3085 | |
3086 | === removed file 'doc/Security.txt' |
3087 | --- doc/Security.txt 2012-04-30 22:09:31 +0000 |
3088 | +++ doc/Security.txt 1970-01-01 00:00:00 +0000 |
3089 | @@ -1,91 +0,0 @@ |
3090 | -[[Security]] |
3091 | -= Security Notes |
3092 | - |
3093 | -Akiban Persistit provides no built-in data access control because it is intended for embedded use in applications that provide their own logical access control. Security-conscious applications must also prevent unauthorized access to Persistit's physical files and to the Persistit API. The following resources must be protected from unauthorized access: |
3094 | - |
3095 | -- Persistit volume files |
3096 | -- configuration properties file, if one is used |
3097 | -- access by unauthorized code to the API exposed by the Persistit library |
3098 | -- the port opened and exposed by Persistit when either the +com.persistit.rmiport+ or +com.persistit.rmihost+ property is set. If you are using Persistit's remote administration feature, be sure to block unauthorized access to the RMI port. |
3099 | -- the <<cliserver>> if instantiated |
3100 | - |
3101 | -In addition to these general deployment considerations, Persistit requires certain permissions in an environment controlled by a security manager. |
3102 | - |
3103 | -Java programs run from the command line typically do not install a security manager, and therefore implicitly grant all permissions. However, when Persistit is used within an Applet, or within any framework that installs a security manager, it is important to understand what permissions are required. |
3104 | - |
3105 | -== Security Domains |
3106 | - |
3107 | -This section assumes a basic understanding of the Java security model. See http://download.oracle.com/javase/1.5.0/docs/guide/security/spec/security-spec.doc2.html[New Protection Mechanisms - Overview of Basic Concepts] for further information. |
3108 | - |
3109 | -Note that when Java is started from the command line, as is often the case in server applications, all security privileges are granted by default. The information in this section is intended for cases where security privileges need to be controlled. |
3110 | - |
3111 | -Akiban Persistit performs various security-sensitive operations: it reads and writes files, it reads system properties, it optionally opens a TCP/IP socket, and it performs various security-sensitive operations related to reflection and serialization. These operations are divided into two categories: those required only by the Persistit library itself, and those required by the application that is using Persistit. For example, the application code must have permission to read and write files, but it does not require permission to access private fields through reflection; only the Persistit library itself needs this permission. The latter operation is called a “privileged” operation because Persistit invokes the access controller's doPrivileged method to establish its permission to perform the privileged operation. |
3112 | - |
3113 | -At a practical level, this means you can create two separate security domains for applications embedding Persistit. One domain is specific to the Persistit library itself, and grants all the permissions required by Persistit, including the privileged permissions. The other domain includes the application, and grants only the non-privileged permissions. |
3114 | - |
3115 | -Using the default java.lang.SecurityManager implementation, you define domains and the permissions available to them in a policy file stored in the user's home directory. For those already familiar with the policy file format, here is a security policy file that illustrates these concepts: |
3116 | - |
3117 | -.Example .java.policy File |
3118 | ----- |
3119 | -grant codeBase "file:/appdir/myapplication.jar" { |
3120 | - permission java.io.FilePermission "e:\\data\\*", "read, write, delete"; |
3121 | - permission java.io.FilePermission "e:\\logs\\*", "read, write, delete"; |
3122 | - permission java.net.SocketPermission "localhost", |
3123 | - "accept, connect, listen, resolve"; |
3124 | -}; |
3125 | - |
3126 | -grant codeBase "file:/lib/akiban-persistit.jar" { |
3127 | - permission java.io.FilePermission "<<ALL FILES>>", "read, write, delete"; |
3128 | - permission java.net.SocketPermission "*:1099-", |
3129 | - "accept, connect, listen, resolve"; |
3130 | - permission java.lang.reflect.ReflectPermission "suppressAccessChecks"; |
3131 | - permission java.io.SerializablePermission "enableSubclassImplementation"; |
3132 | - permission java.util.PropertyPermission "com.persistit.*", "read"; |
3133 | - permission java.lang.RuntimePermission "accessDeclaredMembers"; |
3134 | -}; |
3135 | ----- |
3136 | - |
3137 | -This policy file sets up two security domains. One covers the application code in +myapplication.jar+ and grants just the restricted set of permissions needed by the application, while the other grants additional permissions to the Persistit library. |
3138 | - |
3139 | -Although the file and socket permissions granted by the privileged domain are less restrictive than those granted to +myapplication.jar+, the actual permission granted to running code is the intersection of these two and is therefore restricted to just the set of files and sockets granted to myapplication.jar. |
3140 | - |
3141 | -== Permissions Required for DefaultValueCoder |
3142 | - |
3143 | -DefaultValueCoder performs three security-sensitive operations: |
3144 | - |
3145 | -- It enumerates the declared fields of the class being serialized, |
3146 | -- It reads and writes data from and to those fields using reflection even if they are private, and |
3147 | -- It overrides the default implementations of java.io.ObjectInputStream and java.io.ObjectOutputStream. |
3148 | - |
3149 | -If a SecurityManager is installed then three permissions must be granted to enable this new mechanism: |
3150 | - |
3151 | ----- |
3152 | -java.lang.RuntimePermission "accessDeclaredMembers"; |
3153 | -java.lang.reflect.ReflectPermission("suppressAccessChecks") |
3154 | -java.io.SerializablePermission("enableSubclassImplementation") |
3155 | ----- |
3156 | - |
3157 | -Persistit acquires these permissions through privileged operations, meaning that only the Persistit library domain needs to have them – they do not need to be and should not be granted to the application domain. |
3158 | - |
3159 | -== Permission Required for Reading System Properties |
3160 | - |
3161 | -Persistit attempts to read system properties whose names begin with “com.persistit.” Specific permission to do this is granted by the line |
3162 | - |
3163 | ----- |
3164 | - permission java.util.PropertyPermission "com.persistit.*", "read"; |
3165 | ----- |
3166 | - |
3167 | -Again, only the Persistit library domain needs to have this permission. If this permission is not granted, Persistit ignores all system properties. |
3168 | - |
3169 | -== Permissions Required for File and Socket I/O |
3170 | - |
3171 | -Persistit needs permission to read and write its volume and journal files, to read a configuration properties file and (optionally) write to a log file. File I/O permissions also apply to the source and destination files specified for Import and Export tasks available within the AdminUI utility. In addition, if you specify either the rmihost or rmiport property to enable remote administration, Persistit needs permission to create RMI connections. |
3172 | - |
3173 | -These are not privileged operations, meaning that if the policy establishes separate domains for the application and the Persistit library, both domains must grant permission for all I/O operations. (If they were privileged operations, an untrusted application code could use the Persistit library as a proxy to perform malicious file I/O.) As is defined by the Java security mechanism, when Persistit attempts to open a file, permissions of both the application domain and the Persistit library domains are checked; if the operation is denied by either domain then the attempt fails with a java.security.AccessControlException. |
3174 | - |
3175 | -As specified in the sample policy file above, the Persistit library domain has been granted permissions on `<<ALL FILES>>`. This means that the application domain controls what subset of the file system is accessible. In the example, files may only be read and written to the e:\data and e:\logs directories on a Windows box. (See the Java documentation on Permissions for details on how to construct File and Socket permissions.) |
3176 | - |
3177 | -== Deploying Persistit as an Installed Optional Package |
3178 | - |
3179 | -A convenient way to grant Persistit the permissions required to perform its privileged operations is to install it as an optional package. The Sun Java Runtime Environment treats JAR files located in the <jre-home>/lib/ext directory as optional Java extension classes, and by default grants them the same privileges as Java system classes. If the Persistit library is loaded from this directory then only the application File and Socket privileges need to be granted explicitly through a security policy. To deploy Persistit in this manner simply copy the Persistit library jar file to the appropriate +_jre-home_/lib/ext+ directory. |
3180 | - |
3181 | |
3182 | === added file 'doc/Serialization.rst' |
3183 | --- doc/Serialization.rst 1970-01-01 00:00:00 +0000 |
3184 | +++ doc/Serialization.rst 2012-05-30 18:23:19 +0000 |
3185 | @@ -0,0 +1,250 @@ |
3186 | +.. _Serialization: |
3187 | + |
3188 | +Serializing Object Values |
3189 | +========================= |
3190 | + |
3191 | +Akiban Persistit uses one of several mechanisms to serialize a Java Object into a ``com.persistit.Value``. |
3192 | + |
3193 | +* For the following classes, Persistit provides built-in optimized serialization logic that cannot be overridden: |
3194 | + |
3195 | + * ``java.lang.String`` |
3196 | + * ``java.util.Date`` |
3197 | + * ``java.math.BigInteger`` |
3198 | + * ``java.math.BigDecimal`` |
3199 | + * Wrapper classes for primitive values (``Boolean``, ``Byte``, ``Short``, etc.) |
3200 | + * All arrays (however, the mechanisms described here apply to array elements). |
3201 | + |
3202 | +* An application can register a custom ``com.persistit.encoding.ValueCoder`` to handle serialization of a particular class |
3203 | +* Default serialization using Persistit's built-in serialization mechanism described below, or |
3204 | +* Standard Java serialization as described in http://download.oracle.com/javase/1.5.0/docs/guide/serialization/spec/serial-arch.html[Java Object Serialization Specification]. |
3205 | + |
3206 | +Persistit's default serialization method serializes objects into approximately 33% fewer bytes, and depending on the structure of objects being serialized, is about 40% faster than Java serialization. |
3207 | + |
3208 | +Storing Objects in Persistit |
3209 | +---------------------------- |
3210 | + |
3211 | +To store an object value into a Persistit database, you put the object into the Value field of an Exchange, and then invoke the Exchange's store method as shown in this code fragment: |
3212 | + |
3213 | +.. code-block:: java |
3214 | + |
3215 | + exchange.getValue().put(myObject); |
3216 | + exchange.store(); |
3217 | + |
3218 | +Of course, Persistit cannot actually store a live object on disk. Instead it creates and stores a byte array containing state information about the object. Subsequently you fetch an object from Persistit as follows: |
3219 | + |
3220 | +.. code-block:: java |
3221 | + |
3222 | + exchange.fetch(); |
3223 | + MyClass myObject = (MyClass)exchange.getValue().get(); |
3224 | + |
3225 | +The resulting MyClass instance is a newly constructed object instance that is equivalent - subject to the accuracy of the serialization code - to the original object. This process is equivalent to the serialization and deserialization capabilities provided by java.io.ObjectOutputStream and java.io.ObjectInputStream. |
3226 | + |
3227 | +Persistit makes use of helper classes called “coders” to marshal data between live objects and their stored byte-array representations. Value coders, which implement ``com.persistit.encoding.ValueCoder``, marshal data to and from Value objects; ``com.persistit.encoding.KeyCoder`` implementations do the same for ``com.persistit.Key``s. A value coder provides capability somewhat like the custom serialization logic implemented through ``readObject``, ``writeObject``, ``readExternal`` and ``writeExternal``. However, a value coder can provide this logic for any class without modifying the class itself, which may be important if the class is part of a closed library. |
3228 | + |
3229 | +You may create and register a value coder for almost any class, including classes that are not marked Serializable. The exceptions are those listed which have built-in, non-overridable serialization logic. |
3230 | + |
3231 | +DefaultValueCoder and SerialValueCoder |
3232 | +-------------------------------------- |
3233 | + |
3234 | +When required to serialize or deserialize class with no explicitly defined ``ValueCoder``, Persistit automatically creates and registers one of the following two default ``ValueCoder`` implementations: |
3235 | + |
3236 | +``com.persistit.DefaultValueCoder``:: uses introspection to determine which fields to serialize, and reflection to access and update the fields |
3237 | +``com.persistit.encoding.SerialValueCoder``:: creates instances of ObjectInputStream and ObjectOutputStream to serialize and deserialize the object. |
3238 | + |
3239 | +DefaultValueCoder uses a more compact storage format and is significantly faster than standard Java serialization; however, it imposes certain limitations and trade-offs described below. By default, Persistit will use a DefaultValueCoder. However, you can identify classes that should instead be serialized and deserialized by ``SerialValueCoder`` by specifying the ``serialOverride`` configuration property, which is described below. |
3240 | + |
3241 | +DefaultValueCoder |
3242 | +----------------- |
3243 | + |
3244 | +A DefaultValueCoder uses Java reflection to access and update the fields of an arbitrary object. The set of fields is defined by the Java Object Serialization Specification. By default, these include all non-static, non-transient fields of the current class and its Serializable superclasses. A class may override this default set by specifying an array of ``java.io.ObjectStreamField`` objects in a private final static field named ``serialPersistentFields``, as described in the specification. |
3245 | + |
3246 | +``DefaultValueCoder`` invokes the special methods ``readResolve``, ``writeReplace``, ``readObject`` and ``writeObject``, (or for Externalizable classes, ``writeExternal`` and ``readExternal``) to provide the compatible custom serialization support. To support the ``readObject``/``readExternal`` and ``writeObject``/``writeExternal`` methods, Persistit creates extended implementations of ``java.io.ObjectOutputStream`` and ``java.io.ObjectInputStream``. These use a custom serialization format optimized for writing to a Value's backing byte array. For example, they do not organize data into 1,024-byte blocks, and they factor meta data about classes into a separate class information database so that this information is not repeated in multiple records containing instances of the same class. |
3247 | + |
3248 | +Currently, ``DefaultValueCoder`` does not support the following elements of the serialization API: |
3249 | + |
3250 | +- the ``readObjectNoData`` custom serialization method |
3251 | +- the ``PutFields``/``GetFields`` API of ``ObjectOutputStream`` and ``ObjectInputStream`` |
3252 | +- the ``readLine`` method of ``ObjectInputStream``. |
3253 | + |
3254 | +Constructing Objects upon Deserialization |
3255 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
3256 | + |
3257 | +When deserializing a value, ``DefaultValueCoder`` combines information about the original object's class and the stored field data to reconstruct an object equivalent to the original. To do so it must first construct a new instance of class and then decode and set its serialized fields. |
3258 | + |
3259 | +For compatibility with standard Java serialization, ``DefaultValueCoder`` constructs new object instances of Serializable classes using the same logic as ``ObjectInputStream``, namely: |
3260 | + |
3261 | +If the class is Externalizable, ``DefaultValueCoder`` invokes its public no-argument constructor. (The specification for Externalizable requires the class to have such a constructor.) |
3262 | + |
3263 | +Otherwise, if the class is Serializable, ``DefaultValueCoder`` invokes the no-argument constructor of its nearest non-serializable superclass. |
3264 | + |
3265 | +``DefaultValueCoder`` must use platform-specific logic when constructing instances of Serializable classes: specifically, it invokes the same internal, non-public method as ``ObjectInputStream``. We have verified correct behavior on a wide range of Java runtime environments, but because the implementation uses private methods within various JRE versions, it is possible (though unlikely) that a future JRE will not provide a comparable capability. |
3266 | + |
3267 | +To avoid using platform-specific API calls, you can specify the configuration property:: |
3268 | + |
3269 | + constructorOverride=true |
3270 | + |
3271 | +When this property is ``true``, ``DefaultValueCoder`` requires each object being serialized or deserialized to have a no-argument constructor through which instances will be constructed during deserialization. Unless the class implements Externalizable, that constructor may be private, package-private, protected or public. |
3272 | + |
3273 | +Extending DefaultValueCoder |
3274 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
3275 | + |
3276 | +You can register an extended ``DefaultValueCoder`` to provide custom behavior, including custom logic for constructing instances of a class, as shown here: |
3277 | + |
3278 | +.. code-block:: java |
3279 | + |
3280 | + Persistit.getInstance().getCoderManager().registerValueCoder(MyClass.class, new DefaultValueCoder(MyClass.class) { |
3281 | + public Object get(Value value, Class clazz, CoderContext context) throws ConversionException { |
3282 | + |
3283 | + // Construct the object being deserialized. |
3284 | + Object instance = new MyClass(...custom arguments...); |
3285 | + |
3286 | + // See "registering objects while deserializing" below |
3287 | + value.registerEncodedObject(instance); |
3288 | + |
3289 | + // Load the non-transient, non-static fields |
3290 | + render(value, instance, clazz, context); |
3291 | + |
3292 | + return instance; |
3293 | + } |
3294 | + }); |
3295 | + |
3296 | + |
3297 | + |
3298 | +Security Policy Requirements for DefaultValueCoder |
3299 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
3300 | + |
3301 | +DefaultValueCoder performs security-sensitive operations: (a) it reads and writes data from and to private fields using reflection, and (b) it overrides the default implementations of java.io.ObjectInputStream and java.io.ObjectOutputStream. If a SecurityManager is installed then three permissions must be granted to enable the new mechanism:: |
3302 | + |
3303 | + java.lang.RuntimePermission "accessDeclaredMembers"; |
3304 | + java.lang.reflect.ReflectPermission("suppressAccessChecks") |
3305 | + java.io.SerializablePermission("enableSubclassImplementation") |
3306 | + |
3307 | +See :ref:`Security` for an extended discussion on security policy issues for Persistit. |
3308 | + |
3309 | +SerialValueCoder |
3310 | +---------------- |
3311 | + |
3312 | +``SerialValueCoder`` uses standard Java serialization to store and retrieve object values. Typically this results in slower performance and a more verbose storage format than ``DefaultValueCoder``, but there are a number of reasons why a particular application might require standard Java serialization, including: |
3313 | + |
3314 | +- the security context into which the application will be deployed does not grant the permissions noted above that are required for ``DefaultValueCoder``, |
3315 | +- to avoid Persistit's use of private API calls to construct object instances during deserialization, |
3316 | +- a preference for the use of a standard format defined within the Java platform rather than Persistit's custom format, |
3317 | +- limitations documented above on the API elements available during custom deserialization within DefaultValueCoder, for example non-support of GetField and PutField. |
3318 | + |
3319 | +Your application can specify ``SerialValueCoders`` for specific classes either by explicitly creating and registering them, or by naming them in the com.persistit.serialOverride property. |
3320 | + |
3321 | +To explicitly register a ``SerialValueCoder`` for the class ``MyClass``, do this: |
3322 | + |
3323 | +.. code-block:: java |
3324 | + |
3325 | + ... |
3326 | + Persistit.getInstance().getCoderManager().registerValueCoder( |
3327 | + MyClass.class, |
3328 | + new SerialValueCoder(MyClass.class)); |
3329 | + ... |
3330 | + |
3331 | + |
3332 | +The ``com.persistit.serialOverride`` Configuration Property |
3333 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
3334 | + |
3335 | +The ``serialOverride`` property specifies classes that are to be serialized by ``SerialValueCoder`` rather than ``DefaultValueCoder``. This property affects how Persistit assigns a value coder when none has previously been registered. It does not override or affect explicitly registered coders. |
3336 | + |
3337 | +Names are separated by commas and may contain wild cards. |
3338 | + |
3339 | +The following are valid patterns: |
3340 | + |
3341 | + ``java.io.File`` |
3342 | + Just the File class. |
3343 | + ``java.io.*`` |
3344 | + All classes in the java.io package. |
3345 | + ``java.awt.**`` |
3346 | + All classes in the java.awt package and its sub-packages |
3347 | + ``java.util.*Map`` |
3348 | + All of the Map classes in the java.util. |
3349 | + ``**`` |
3350 | + All classes in all packages |
3351 | + |
3352 | +More precisely, ``serialOverride`` specifies a comma-delimited list of zero or more patterns, each of which is either a fully-qualified class name or pattern that has within it exactly one wild card. The wild card “\*” replaces any sequence of characters other than a period (“.”), while “\*\*” replaces any sequence of characters including periods. For example:: |
3353 | + |
3354 | + ``serialOverride=org.apache.**,com.mypkg.serialstuff.*,com.mypkg.MyClass`` |
3355 | + |
3356 | +Like all configuration properties, you may specify this in the persistit.properties file or as a system property through a Java command-line argument in the form:: |
3357 | + |
3358 | + ``-Dcom.persistit.serialOverride=...`` |
3359 | + |
3360 | +Registering Objects in a Custom ``ValueCoder`` |
3361 | +---------------------------------------------- |
3362 | + |
3363 | +In a custom ``ValueCoder`` implementation, the ``get`` method is responsible for constructing and populating an instance of an object. The following pattern should be used when implementing the get method: |
3364 | + |
3365 | +.. code-block:: java |
3366 | + |
3367 | + public void get(Value value, Class clazz, CoderContext context) throws ConversionException { |
3368 | + // Construct the object being deserialized. |
3369 | + // |
3370 | + Object instance = ...constructor for the object... |
3371 | + |
3372 | + // Associate a handle with the newly |
3373 | + // created instance. |
3374 | + // |
3375 | + value.registerEncodedObject(instance); |
3376 | + |
3377 | + // Populate the object's internal state |
3378 | + // |
3379 | + ... load the fields – for example, by calling render... |
3380 | + |
3381 | + return instance; |
3382 | + } |
3383 | + |
3384 | +The purpose of the ``registerEncodedObject`` method is to record the association between the newly created object and an internal integer-valued handle that may be used subsequently in the serialization stream to refer to that object. This mechanism supports objects that may have fields that refer either indirectly or indirectly back to the same object – i.e., that participate in a cyclical reference graph. |
3385 | + |
3386 | +As a concrete example, consider a Person class with a spouse field such that for married couple p and q, p.spouse is q and q.spouse is p. When Persistit serializes p it also serializes q, but when it serializes q's spouse field, it records a reference handle associated with the already-serialized instance of p rather than writing a new copy of p in the serialization stream. Upon deserializing q, Persistit looks up the object for the recorded handle to correctly associate the already-deserialized p instance with q. |
3387 | + |
3388 | +Whenever you implement a custom ``get()`` method in any ``ValueCoder``, you must notify the underlying Value object about the newly created object by calling registerEncodedObject before deserializing its fields so that any back-references made within serialized fields of that object can find the object correctly. |
3389 | + |
3390 | +``Value.toString()`` and ``decodeDisplayable`` |
3391 | +---------------------------------------------- |
3392 | + |
3393 | +In many cases it is not very useful simply to display the result of evaluating ``toString()`` on an object. The default toString method inherited from Object conveys just a class name and a memory handle. In addition, for remote operations of AdminUI, it may not even be feasible to construct a deserialized object for each record. Therefore, ``com.persistit.Value`` provides a specialized ``toString()`` method to render an arbitrary object value into a legible string. The AdminUI utility uses this facility to summarize the data contained in a Tree. |
3394 | + |
3395 | +Persistit creates a String value loading the object's class, using the following algorithm: |
3396 | + |
3397 | +- If the state represented by this Value is undefined, then return "undefined". |
3398 | +- If the state is null or a boolean, return "null" "false", or "true". |
3399 | +- If the value represents a primitive type, return the string representation of the value, prefixed by "(byte)", "(short)", "(char)", "(long)", or "(float)" for the corresponding types. Values of type int and double are presented without prefix to reduce clutter. |
3400 | +- If the value represents a String, return a modified form of the string enclosed in double quotes. For each character of the string, if it is a double quote replace it by "\"", otherwise if it is outside of the printable ASCII character set replace the character in the modified string by "\b", "\t", "\n", "\r" or "\uNNNN" such that the modified string would be a valid Java string constant. |
3401 | +- If the value represents a wrapper for a primitive value (i.e., a java.lang.Boolean, java.lang.Byte, etc.) return the string representation of the value prefixed by "(Boolean)", "(Byte)", "(Short)", "(Character)", "(Integer)", "(Long)", "(Float)" or "(Double)". The package name java.lang is removed to reduce clutter. |
3402 | +- If the value represents a java.util.Date, return a formatted representation of the date using the format specified by Key.SDF. This is a readable format that displays the date with full precision, including milliseconds. |
3403 | +- If the value represents an array, return a list of comma-separated element values surrounded by square brackets. |
3404 | +- If the value represents one of the standard Collection implementations in the java.util package, then return a comma-separated list of values surrounded by square brackets. |
3405 | +- If the value represents one of the standard Map implementations in the java.util package, then return a comma-separated list of key/value pairs surrounded by square brackets. Each key/value pair is represented by a string in the form key->value. |
3406 | +- If the value represents an object of a class for which there is a registered com.persistit.encoding.ValueDisplayer, invoke the displayer's display method to format a displayable representation of the object. |
3407 | +- If the value represents an object that has been stored using the version default serialization mechanism described above, return the class name of the object followed by a comma-separated tuple, enclosed within curly brace characters, representing the value of each field of the object. |
3408 | +- If the value represents an object encoded through standard Java serialization, return the string "(Serialized-object)" followed by a sequence of hex digits representing the serialized bytes. Note that this process does not attempt to deserialize the object. |
3409 | +- If the value represents an object that has already been represented within the formatted result - for example, if a Collection contains two references to the same object - then instead of creating an additional string representing the second or subsequent instance, emit a back reference pointer in the form @NNN where NNN is the character offset within the displayable string where the first instance was found. (This does not apply to strings and the primitive wrapper classes.) |
3410 | + |
3411 | +For example, consider a Person having for date of birth, first name, last name, salary and friends, an array of other Person objects. The result returned by toString() on a Value representing Mary Smith who has a friend John Smith, might appear as follows:: |
3412 | + |
3413 | + (Person){(Date)19490826000000.000-0400,"Mary","Jones",(long)75000,[ |
3414 | + (Person){(Date)19550522000000.000-0400,"John","Smith",(long)68000,[@0]}]} |
3415 | + |
3416 | +In this example, John Smith's friends array contains a back reference to Mary Jones in the form "@0" because Mary's displayable reference starts at the beginning of the string. |
3417 | + |
3418 | + |
3419 | +PersistitReference |
3420 | +------------------ |
3421 | + |
3422 | +In general, serializing an object that contains references to other objects requires all the referenced objects also to be serialized. For an object connected to a large reference graph, it may be impractical or even semantically incorrect to serialize the entire graph. |
3423 | + |
3424 | +One way to control the serialization graph for such an object is to write a custom ValueCoder; the custom ValueCoder can store key values for looking up the referenced object, rather than the object itself. The ValueCoderDemo.java program demonstrates how this can be done. |
3425 | + |
3426 | +The ``com.persistit.ref.PersistitReference`` interface, and its abstract subclasses, provide an alternative mechanism for breaking up an object reference graph. It requires no custom ValueCoder, but does impact the design of application classes. In addition, you will need to write a concrete implementation of either com.persistit.ref.AbstractReference or com.persistit.ref.AbstractWeakReference based on the actual storage structure of your object graph. |
3427 | + |
3428 | +ObjectCache |
3429 | +----------- |
3430 | + |
3431 | +A ``com.persistit.Value`` object holds the serialized, encoded state of a primitive value of an object. Each time you invoke the get method on a Value, Persistit generates a new copy of the object deserialized from this Value. Persistit does not implicitly cache deserialized objects. However, the ``com.persistit.encoding.ObjectCache`` class provides a simple mechanism for applications that need to maintain an in-memory cache of of objects from Persistit. ``ObjectCache`` works somewhat like a specialized version of java.util.WeakHashMap. |
3432 | + |
3433 | +``ObjectCache`` has ``put``, ``get`` and ``remove`` methods much like a normal Map implementation. However, when storing an object value with the supplied ``com.persistit.Key``, ``ObjectCache`` constructs a new, immutable ``com.persistit.KeyState`` object to hold as an internal key. This is necessary because ``Key`` objects change value as they are used. |
3434 | + |
3435 | +Each ``ObjectCache`` entry holds its object value as a ``SoftReference``, making it available for garbage collection when space is needed. |
3436 | |
3437 | === removed file 'doc/Serialization.txt' |
3438 | --- doc/Serialization.txt 2012-04-30 22:09:31 +0000 |
3439 | +++ doc/Serialization.txt 1970-01-01 00:00:00 +0000 |
3440 | @@ -1,246 +0,0 @@ |
3441 | -[[Serialization]] |
3442 | -= Serializing Object Values |
3443 | - |
3444 | -Akiban Persistit uses one of several mechanisms to serialize a Java Object into a +com.persistit.Value+. |
3445 | - |
3446 | -- For the following classes, Persistit provides built-in optimized serialization logic that cannot be overridden: |
3447 | - |
3448 | -* +java.lang.String+ |
3449 | -* +java.util.Date+ |
3450 | -* +java.math.BigInteger+ |
3451 | -* +java.math.BigDecimal+ |
3452 | -* Wrapper classes for primitive values (+Boolean+, +Byte+, +Short+, etc.) |
3453 | -* All arrays (however, the mechanisms described here apply to array elements). |
3454 | - |
3455 | -- An application can register a custom +com.persistit.encoding.ValueCoder+ to handle serialization of a particular class |
3456 | -- Default serialization using Persistit's built-in serialization mechanism described below, or |
3457 | -- Standard Java serialization as described in http://download.oracle.com/javase/1.5.0/docs/guide/serialization/spec/serial-arch.html[Java Object Serialization Specification]. |
3458 | - |
3459 | -Persistit's default serialization method serializes objects into approximately 33% fewer bytes, and depending on the structure of objects being serialized, is about 40% faster than Java serialization. |
3460 | - |
3461 | -== Storing Objects in Persistit |
3462 | - |
3463 | -To store an object value into a Persistit database, you put the object into the Value field of an Exchange, and then invoke the Exchange's store method as shown in this code fragment: |
3464 | - |
3465 | -[source,java] |
3466 | ----- |
3467 | - exchange.getValue().put(myObject); |
3468 | - exchange.store(); |
3469 | ----- |
3470 | - |
3471 | -Of course, Persistit cannot actually store a live object on disk. Instead it creates and stores a byte array containing state information about the object. Subsequently you fetch an object from Persistit as follows: |
3472 | - |
3473 | -[source,java] |
3474 | ----- |
3475 | - exchange.fetch(); |
3476 | - MyClass myObject = (MyClass)exchange.getValue().get(); |
3477 | ----- |
3478 | - |
3479 | -The resulting MyClass instance is a newly constructed object instance that is equivalent - subject to the accuracy of the serialization code - to the original object. This process is equivalent to the serialization and deserialization capabilities provided by java.io.ObjectOutputStream and java.io.ObjectInputStream. |
3480 | - |
3481 | -Persistit makes use of helper classes called “coders” to marshal data between live objects and their stored byte-array representations. Value coders, which implement +com.persistit.encoding.ValueCoder+, marshal data to and from Value objects; +com.persistit.encoding.KeyCoder+ implementations do the same for +com.persistit.Key+ s. A value coder provides capability somewhat like the custom serialization logic implemented through +readObject+, +writeObject+, +readExternal+ and +writeExternal+. However, a value coder can provide this logic for any class without modifying the class itself, which may be important if the class is part of a closed library. |
3482 | - |
3483 | -You may create and register a value coder for almost any class, including classes that are not marked Serializable. The exceptions are those listed which have built-in, non-overridable serialization logic. |
3484 | - |
3485 | -=== DefaultValueCoder and SerialValueCoder |
3486 | - |
3487 | -When required to serialize or deserialize class with no explicitly defined +ValueCoder+, Persistit automatically creates and registers one of the following two default +ValueCoder+ implementations: |
3488 | - |
3489 | -+com.persistit.DefaultValueCoder+:: uses introspection to determine which fields to serialize, and reflection to access and update the fields |
3490 | -+com.persistit.encoding.SerialValueCoder+:: creates instances of ObjectInputStream and ObjectOutputStream to serialize and deserialize the object. |
3491 | - |
3492 | -DefaultValueCoder uses a more compact storage format and is significantly faster than standard Java serialization; however, it imposes certain limitations and trade-offs described below. By default, Persistit will use a DefaultValueCoder. However, you can identify classes that should instead be serialized and deserialized by +SerialValueCoder+ by specifying the +serialOverride+ configuration property, which is described below. |
3493 | - |
3494 | -== DefaultValueCoder |
3495 | - |
3496 | -A DefaultValueCoder uses Java reflection to access and update the fields of an arbitrary object. The set of fields is defined by the Java Object Serialization Specification. By default, these include all non-static, non-transient fields of the current class and its Serializable superclasses. A class may override this default set by specifying an array of +java.io.ObjectStreamField+ objects in a private final static field named +serialPersistentFields+, as described in the specification. |
3497 | - |
3498 | -+DefaultValueCoder+ invokes the special methods +readResolve+, +writeReplace+, +readObject+ and +writeObject+, (or for Externalizable classes, +writeExternal+ and +readExternal+) to provide the compatible custom serialization support. To support the +readObject+/+readExternal+ and +writeObject+/+writeExternal+ methods, Persistit creates extended implementations of +java.io.ObjectOutputStream+ and +java.io.ObjectInputStream+. These use a custom serialization format optimized for writing to a Value's backing byte array. For example, they do not organize data into 1,024-byte blocks, and they factor meta data about classes into a separate class information database so that this information is not repeated in multiple records containing instances of the same class. |
3499 | - |
3500 | -Currently, +DefaultValueCoder+ does not support the following elements of the serialization API: |
3501 | - |
3502 | -- the +readObjectNoData+ custom serialization method |
3503 | -- the +PutFields+/+GetFields+ API of +ObjectOutputStream+ and +ObjectInputStream+ |
3504 | -- the +readLine+ method of +ObjectInputStream+. |
3505 | - |
3506 | -=== Constructing Objects upon Deserialization |
3507 | - |
3508 | -When deserializing a value, +DefaultValueCoder+ combines information about the original object's class and the stored field data to reconstruct an object equivalent to the original. To do so it must first construct a new instance of class and then decode and set its serialized fields. |
3509 | - |
3510 | -For compatibility with standard Java serialization, +DefaultValueCoder+ constructs new object instances of Serializable classes using the same logic as +ObjectInputStream+, namely: |
3511 | - |
3512 | -If the class is Externalizable, +DefaultValueCoder+ invokes its public no-argument constructor. (The specification for Externalizable requires the class to have such a constructor.) |
3513 | - |
3514 | -Otherwise, if the class is Serializable, +DefaultValueCoder+ invokes the no-argument constructor of its nearest non-serializable superclass. |
3515 | - |
3516 | -+DefaultValueCoder+ must use platform-specific logic when constructing instances of Serializable classes: specifically, it invokes the same internal, non-public method as +ObjectInputStream+. We have verified correct behavior on a wide range of Java runtime environments, but because the implementation uses private methods within various JRE versions, it is possible (though unlikely) that a future JRE will not provide a comparable capability. |
3517 | - |
3518 | -To avoid using platform-specific API calls, you can specify the configuration property |
3519 | - |
3520 | ----- |
3521 | - constructorOverride=true |
3522 | ----- |
3523 | - |
3524 | -When this property is +true+, +DefaultValueCoder+ requires each object being serialized or deserialized to have a no-argument constructor through which instances will be constructed during deserialization. Unless the class implements Externalizable, that constructor may be private, package-private, protected or public. |
3525 | - |
3526 | -=== Extending DefaultValueCoder |
3527 | - |
3528 | -You can register an extended +DefaultValueCoder+ to provide custom behavior, including custom logic for constructing instances of a class, as shown here: |
3529 | - |
3530 | -[source,java] |
3531 | ------ |
3532 | - Persistit.getInstance().getCoderManager().registerValueCoder(MyClass.class, new DefaultValueCoder(MyClass.class) { |
3533 | - public Object get(Value value, Class clazz, CoderContext context) throws ConversionException { |
3534 | - |
3535 | - // Construct the object being deserialized. |
3536 | - Object instance = new MyClass(...custom arguments...); |
3537 | - |
3538 | - // See "registering objects while deserializing" below |
3539 | - value.registerEncodedObject(instance); |
3540 | - |
3541 | - // Load the non-transient, non-static fields |
3542 | - render(value, instance, clazz, context); |
3543 | - |
3544 | - return instance; |
3545 | - } |
3546 | - }); |
3547 | ----- |
3548 | - |
3549 | - |
3550 | - |
3551 | -=== Security Policy Requirements for DefaultValueCoder |
3552 | - |
3553 | -DefaultValueCoder performs security-sensitive operations: (a) it reads and writes data from and to private fields using reflection, and (b) it overrides the default implementations of java.io.ObjectInputStream and java.io.ObjectOutputStream. If a SecurityManager is installed then three permissions must be granted to enable the new mechanism: |
3554 | - |
3555 | ----- |
3556 | -java.lang.RuntimePermission "accessDeclaredMembers"; |
3557 | -java.lang.reflect.ReflectPermission("suppressAccessChecks") |
3558 | -java.io.SerializablePermission("enableSubclassImplementation") |
3559 | ----- |
3560 | - |
3561 | -See <<Security>> for an extended discussion on security policy issues for Persistit. |
3562 | - |
3563 | -== SerialValueCoder |
3564 | - |
3565 | -+SerialValueCoder+ uses standard Java serialization to store and retrieve object values. Typically this results in slower performance and a more verbose storage format than +DefaultValueCoder+, but there are a number of reasons why a particular application might require standard Java serialization, including: |
3566 | - |
3567 | -- the security context into which the application will be deployed does not grant the permissions noted above that are required for +DefaultValueCoder+, |
3568 | -- to avoid Persistit's use of private API calls to construct object instances during deserialization, |
3569 | -- a preference for the use of a standard format defined within the Java platform rather than Persistit's custom format, |
3570 | -- limitations documented above on the API elements available during custom deserialization within DefaultValueCoder, for example non-support of GetField and PutField. |
3571 | - |
3572 | -Your application can specify +SerialValueCoders+ for specific classes either by explicitly creating and registering them, or by naming them in the com.persistit.serialOverride property. |
3573 | - |
3574 | -To explicitly register a +SerialValueCoder+ for the class +MyClass+, do this: |
3575 | - |
3576 | -[source,java] |
3577 | ----- |
3578 | - ... |
3579 | - Persistit.getInstance().getCoderManager().registerValueCoder( |
3580 | - MyClass.class, |
3581 | - new SerialValueCoder(MyClass.class)); |
3582 | - ... |
3583 | ----- |
3584 | - |
3585 | - |
3586 | -=== The +com.persistit.serialOverride+ Configuration Property |
3587 | - |
3588 | -The +serialOverride+ property specifies classes that are to be serialized by +SerialValueCoder+ rather than +DefaultValueCoder+. This property affects how Persistit assigns a value coder when none has previously been registered. It does not override or affect explicitly registered coders. |
3589 | - |
3590 | -Names are separated by commas and may contain wild cards. |
3591 | - |
3592 | -The following are valid patterns: |
3593 | - |
3594 | -+java.io.File+:: Just the File class. |
3595 | -+java.io.*+:: All classes in the java.io package. |
3596 | -+java.awt.**+:: All classes in the java.awt package and its sub-packages |
3597 | -+java.util.*Map+:: All of the Map classes in the java.util. |
3598 | -+**+:: All classes in all packages |
3599 | - |
3600 | -More precisely, +serialOverride+ specifies a comma-delimited list of zero or more patterns, each of which is either a fully-qualified class name or pattern that has within it exactly one wild card. The wild card “\*” replaces any sequence of characters other than a period (“.”), while “\*\*” replaces any sequence of characters including periods. For example: |
3601 | - |
3602 | ----- |
3603 | -+serialOverride=org.apache.**,com.mypkg.serialstuff.*,com.mypkg.MyClass+ |
3604 | ----- |
3605 | - |
3606 | -Like all configuration properties, you may specify this in the persistit.properties file or as a system property through a Java command-line argument in the form: |
3607 | - |
3608 | ----- |
3609 | -+-Dcom.persistit.serialOverride=...+ |
3610 | ----- |
3611 | - |
3612 | -== Registering Objects in a Custom +ValueCoder+ |
3613 | - |
3614 | -In a custom +ValueCoder+ implementation, the +get+ method is responsible for constructing and populating an instance of an object. The following pattern should be used when implementing the get method: |
3615 | - |
3616 | -[source,java] |
3617 | ----- |
3618 | -public void get(Value value, Class clazz, CoderContext context) throws ConversionException { |
3619 | - // Construct the object being deserialized. |
3620 | - // |
3621 | - Object instance = ...constructor for the object... |
3622 | - |
3623 | - // Associate a handle with the newly |
3624 | - // created instance. |
3625 | - // |
3626 | - value.registerEncodedObject(instance); |
3627 | - |
3628 | - // Populate the object's internal state |
3629 | - // |
3630 | - ... load the fields – for example, by calling render... |
3631 | - |
3632 | - return instance; |
3633 | -} |
3634 | ----- |
3635 | - |
3636 | -The purpose of the +registerEncodedObject+ method is to record the association between the newly created object and an internal integer-valued handle that may be used subsequently in the serialization stream to refer to that object. This mechanism supports objects that may have fields that refer either indirectly or indirectly back to the same object – i.e., that participate in a cyclical reference graph. |
3637 | - |
3638 | -As a concrete example, consider a Person class with a spouse field such that for married couple p and q, p.spouse is q and q.spouse is p. When Persistit serializes p it also serializes q, but when it serializes q's spouse field, it records a reference handle associated with the already-serialized instance of p rather than writing a new copy of p in the serialization stream. Upon deserializing q, Persistit looks up the object for the recorded handle to correctly associate the already-deserialized p instance with q. |
3639 | - |
3640 | -Whenever you implement a custom +get()+ method in any +ValueCoder+, you must notify the underlying Value object about the newly created object by calling registerEncodedObject before deserializing its fields so that any back-references made within serialized fields of that object can find the object correctly. |
3641 | - |
3642 | -== +Value.toString()+ and +decodeDisplayable+ |
3643 | - |
3644 | -In many cases it is not very useful simply to display the result of evaluating +toString()+ on an object. The default toString method inherited from Object conveys just a class name and a memory handle. In addition, for remote operations of AdminUI, it may not even be feasible to construct a deserialized object for each record. Therefore, +com.persistit.Value+ provides a specialized +toString()+ method to render an arbitrary object value into a legible string. The AdminUI utility uses this facility to summarize the data contained in a Tree. |
3645 | - |
3646 | -Persistit creates a String value loading the object's class, using the following algorithm: |
3647 | - |
3648 | -- If the state represented by this Value is undefined, then return "undefined". |
3649 | -- If the state is null or a boolean, return "null" "false", or "true". |
3650 | -- If the value represents a primitive type, return the string representation of the value, prefixed by "(byte)", "(short)", "(char)", "(long)", or "(float)" for the corresponding types. Values of type int and double are presented without prefix to reduce clutter. |
3651 | -- If the value represents a String, return a modified form of the string enclosed in double quotes. For each character of the string, if it is a double quote replace it by "\"", otherwise if it is outside of the printable ASCII character set replace the character in the modified string by "\b", "\t", "\n", "\r" or "\uNNNN" such that the modified string would be a valid Java string constant. |
3652 | -- If the value represents a wrapper for a primitive value (i.e., a java.lang.Boolean, java.lang.Byte, etc.) return the string representation of the value prefixed by "(Boolean)", "(Byte)", "(Short)", "(Character)", "(Integer)", "(Long)", "(Float)" or "(Double)". The package name java.lang is removed to reduce clutter. |
3653 | -- If the value represents a java.util.Date, return a formatted representation of the date using the format specified by Key.SDF. This is a readable format that displays the date with full precision, including milliseconds. |
3654 | -- If the value represents an array, return a list of comma-separated element values surrounded by square brackets. |
3655 | -- If the value represents one of the standard Collection implementations in the java.util package, then return a comma-separated list of values surrounded by square brackets. |
3656 | -- If the value represents one of the standard Map implementations in the java.util package, then return a comma-separated list of key/value pairs surrounded by square brackets. Each key/value pair is represented by a string in the form key->value. |
3657 | -- If the value represents an object of a class for which there is a registered com.persistit.encoding.ValueDisplayer, invoke the displayer's display method to format a displayable representation of the object. |
3658 | -- If the value represents an object that has been stored using the version default serialization mechanism described above, return the class name of the object followed by a comma-separated tuple, enclosed within curly brace characters, representing the value of each field of the object. |
3659 | -- If the value represents an object encoded through standard Java serialization, return the string "(Serialized-object)" followed by a sequence of hex digits representing the serialized bytes. Note that this process does not attempt to deserialize the object. |
3660 | -- If the value represents an object that has already been represented within the formatted result - for example, if a Collection contains two references to the same object - then instead of creating an additional string representing the second or subsequent instance, emit a back reference pointer in the form @NNN where NNN is the character offset within the displayable string where the first instance was found. (This does not apply to strings and the primitive wrapper classes.) |
3661 | - |
3662 | -For example, consider a Person having for date of birth, first name, last name, salary and friends, an array of other Person objects. The result returned by toString() on a Value representing Mary Smith who has a friend John Smith, might appear as follows: |
3663 | - |
3664 | ----- |
3665 | - (Person){(Date)19490826000000.000-0400,"Mary","Jones",(long)75000,[ |
3666 | - (Person){(Date)19550522000000.000-0400,"John","Smith",(long)68000,[@0]}]} |
3667 | ----- |
3668 | - |
3669 | -In this example, John Smith's friends array contains a back reference to Mary Jones in the form "@0" because Mary's displayable reference starts at the beginning of the string. |
3670 | - |
3671 | - |
3672 | -== PersistitReference |
3673 | - |
3674 | -In general, serializing an object that contains references to other objects requires all the referenced objects also to be serialized. For an object connected to a large reference graph, it may be impractical or even semantically incorrect to serialize the entire graph. |
3675 | - |
3676 | -One way to control the serialization graph for such an object is to write a custom ValueCoder; the custom ValueCoder can store key values for looking up the referenced object, rather than the object itself. The ValueCoderDemo.java program demonstrates how this can be done. |
3677 | - |
3678 | -The +com.persistit.ref.PersistitReference+ interface, and its abstract subclasses, provide an alternative mechanism for breaking up an object reference graph. It requires no custom ValueCoder, but does impact the design of application classes. In addition, you will need to write a concrete implementation of either com.persistit.ref.AbstractReference or com.persistit.ref.AbstractWeakReference based on the actual storage structure of your object graph. |
3679 | - |
3680 | -== ObjectCache |
3681 | - |
3682 | -A +com.persistit.Value+ object holds the serialized, encoded state of a primitive value of an object. Each time you invoke the get method on a Value, Persistit generates a new copy of the object deserialized from this Value. Persistit does not implicitly cache deserialized objects. However, the +com.persistit.encoding.ObjectCache+ class provides a simple mechanism for applications that need to maintain an in-memory cache of of objects from Persistit. +ObjectCache+ works somewhat like a specialized version of java.util.WeakHashMap. |
3683 | - |
3684 | -+ObjectCache+ has +put+, +get+ and +remove+ methods much like a normal Map implementation. However, when storing an object value with the supplied +com.persistit.Key+, +ObjectCache+ constructs a new, immutable +com.persistit.KeyState+ object to hold as an internal key. This is necessary because +Key+ objects change value as they are used. |
3685 | - |
3686 | -Each +ObjectCache+ entry holds its object value as a +SoftReference+, making it available for garbage collection when space is needed. |
3687 | |
3688 | === removed file 'doc/TOC.txt' |
3689 | --- doc/TOC.txt 2012-04-25 18:13:07 +0000 |
3690 | +++ doc/TOC.txt 1970-01-01 00:00:00 +0000 |
3691 | @@ -1,19 +0,0 @@ |
3692 | -Akiban Persistit User Guide |
3693 | -=========================== |
3694 | -Peter Beaman <pbeaman@akiban.com> |
3695 | -:toc: |
3696 | -:doctype: book |
3697 | -:icons: |
3698 | -:numbered: |
3699 | -:website: http://www.akiban.com/persistit/ |
3700 | - |
3701 | -@GettingStarted.txt |
3702 | -@BasicAPI.txt |
3703 | -@Transactions.txt |
3704 | -@PhysicalStorage.txt |
3705 | -@Configuration.txt |
3706 | -@Management.txt |
3707 | -@Security.txt |
3708 | -@Serialization.txt |
3709 | -@Miscellaneous.txt |
3710 | - |
3711 | |
3712 | === added file 'doc/Transactions.rst' |
3713 | --- doc/Transactions.rst 1970-01-01 00:00:00 +0000 |
3714 | +++ doc/Transactions.rst 2012-05-30 18:23:19 +0000 |
3715 | @@ -0,0 +1,200 @@ |
3716 | +.. _Transactions: |
3717 | + |
3718 | +Transactions |
3719 | +============ |
3720 | + |
3721 | +Akiban Persistit supports transactions with multi-version concurrency control (MVCC) using a protocol called Snapshot Isolation (SI). An application calls ``com.persistit.Transaction#begin``, ``com.persistit.Transaction#commit``, ``com.persistit.Transaction#rollback# and ``com.persistit.Transaction#end`` methods to control the current transaction scope explicitly. A Transaction allows an application to execute multiple database operations in an atomic, consistent, isolated and durable (ACID) manner. |
3722 | + |
3723 | +Applications manage transactions through an instance of a ``com.persistit.Transaction`` object. ``Transaction`` does not represent a single transaction, but is instead a context in which a thread may perform many sequential transactions. The general pattern is that the application gets the current thread’s ``Transaction`` instance, calls its ``begin`` method, performs work, calls ``commit`` and finally ``end``. The thread uses the same ``Transaction`` instance repeatedly. Generally each thread has one ``Transaction`` that lasts for the entire life of the thread (but see com.persistit.Transaction#_threadManagement for a mechanism that allows a transaction to be serviced by multiple threads). |
3724 | + |
3725 | +Using Transactions |
3726 | +------------------ |
3727 | + |
3728 | +The following code fragment performs two store operations within the scope of a transaction: |
3729 | + |
3730 | +.. code-block:: java |
3731 | + |
3732 | + // |
3733 | + // Get the transaction context for the current thread. |
3734 | + // |
3735 | + Transaction txn = myExchange.getTransaction(); |
3736 | + int remainingRetries = RETRY_COUNT; |
3737 | + for (;;) { |
3738 | + txn.begin(); |
3739 | + try { |
3740 | + myExchange.getValue().put("First value"); |
3741 | + myExchange.clear().append(1).store(); |
3742 | + myExchange.getValue().put("Second value"); |
3743 | + myExchange.clear().append(2).store(); |
3744 | + // Required to commit the transaction |
3745 | + txn.commit(); |
3746 | + break; |
3747 | + } catch (RollbackException re) { |
3748 | + // perform any special rollback handling |
3749 | + // allow loop to repeat until commit succeeds or retries |
3750 | + // too many times. |
3751 | + if (--remainingRetries < 0) { |
3752 | + throw new TransactionFailedException(); |
3753 | + } |
3754 | + } catch (PersistitException pe) { |
3755 | + // handle other Persistit exception |
3756 | + } finally { |
3757 | + // Required to end the scope of a transaction. |
3758 | + txn.end(); |
3759 | + } |
3760 | + } |
3761 | + |
3762 | +This example catches ``com.persistit.exception.RollbackException`` which can be thrown by any Persistit operation within the scope of a transaction, including ``commit``. Any code explicitly running within the scope of a transaction should be designed to handle rollbacks. |
3763 | + |
3764 | +This example also uses a *try/finally* block to ensure every call to ``begin`` has a matching call to ``end``. This code pattern is mandatory: it is critical to correct transaction nesting behavior. |
3765 | + |
3766 | +One convenient way to do this is to encapsulate the logic of a transaction in an implementation of ``com.persisitit.TransactionRunnable`` interface. The ``com.persistit.Transaction#run`` method automatically provides logic to begin the transaction, execute the TransactionRunnable and commit the transaction, repeating the process until no rollback is thrown or a maximum retry count is reached. For example, the code fragment shown above can be rewritten as: |
3767 | + |
3768 | +.. code-block:: java |
3769 | + |
3770 | + // |
3771 | + // Get the transaction context for the current thread. |
3772 | + // |
3773 | + Transaction txn = myExchange.getTransaction(); |
3774 | + // |
3775 | + // Perform the transaction with the following parameters: |
3776 | + // - try to commit it up to 10 times |
3777 | + // - delay 2 milliseconds before each retry |
3778 | + // - use the group commit durability policy |
3779 | + // |
3780 | + txn.run(new TransactionRunnable() { |
3781 | + public void run() throws PersistitException { |
3782 | + myExchange.getValue().put("First value"); |
3783 | + myExchange.clear().append(1).store(); |
3784 | + myExchange.getValue().put("Second value"); |
3785 | + myExchange.clear().append(2).store(); |
3786 | + } |
3787 | + }, 10, 2, CommitPolicy.GROUP); |
3788 | + |
3789 | +Mixing Transactional and Non-Transactional Operations |
3790 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
3791 | + |
3792 | +Database operations running outside the scope of an explicitly defined transaction are never subject to rollback and therefore do not require retry logic. However, such operations are also not guaranteed to be durable in the event of a system crash. Further, such operations are not isolated. Read operations performed outside of a transaction can read uncommitted updates, and updates performed outside of a transaction are visible within transactions. In other words, non-transactional reads and writes may break both the durability and isolation of concurrently executing transactions. Therefore it is strongly recommended that in an application that relies on transactions, all interactions with the database should use transactions. |
3793 | + |
3794 | +Optimistic Transaction Scheduling |
3795 | +--------------------------------- |
3796 | + |
3797 | +To achieve high performance and scalability, Persistit supports an optimistic transaction scheduling protocol called MVCC with http://wikipedia.org/wiki/Snapshot_isolation[Snapshot Isolation]. Under this protocol multiple threads are permitted to execute transactions at full speed without blocking until a potentially inconsistent state is recognized. At that point a transaction suspected of causing the inconsistent state is automatically forced to roll back. |
3798 | + |
3799 | +Optimistic scheduling works because transactions usually do not collide, especially when individual database operations are fast, and so in practice transactions are seldom rolled back. But because any transaction may be rolled back at any point, applications must be designed carefully to avoid unintended side-effects. For example, a transaction should never perform non-repeatable or externally visible operations such as file or network I/O within its scope. |
3800 | + |
3801 | +Snapshot Isolation |
3802 | +^^^^^^^^^^^^^^^^^^ |
3803 | + |
3804 | +Persistit schedules concurrently executing transactions optimistically, without locking any database records. Instead, Persistit uses the well-known Snapshot Isolation protocol to achieve atomicity and isolation. While transactions are modifying data, Persistit maintains multiple versions of values being modified. Each version is labeled with the commit timestamp of the transaction that modified it. Whenever a transaction reads a value that has been modified by other transactions, it gets the latest version that was committed before its own start timestamp. In other words, all read operations are performed as if from a "snapshot" of the state of the database made at the transaction's start timestamp - hence the name "Snapshot Isolation." |
3805 | + |
3806 | +.. _Pruning: |
3807 | + |
3808 | +Pruning |
3809 | +^^^^^^^ |
3810 | + |
3811 | +Given that all updates written through transactions are created as versions within the MVCC scheme, a large number of versions can accumulate over time. Persistit reduces this proliferation through an activity called "pruning." Pruning resolves the final state of each version by removing any versions created by aborted transactions and removing obsolete versions no longer needed by other transactions. If a value contains only one version and the commit timestamp of the transaction that created it is before the start of any currently running transaction, that value is called *primordial*. The goal of pruning is to reduce most or all values in the database to their primordial states because updating and reading primordial values is more efficient than than managing multiple version values. Pruning happens automatically and is generally not visible to the application. |
3812 | + |
3813 | +Rollbacks |
3814 | +^^^^^^^^^ |
3815 | + |
3816 | +Usually Snapshot Isolation allows concurrent transactions to commit without interference but this is not always the case. Two concurrent transactions that attempt to modify the same Persistit key/value pair before they commit are said to have a "write-write dependency". To avoid anomalous results one of them must abort, rolling back any other updates it may also have created, and retry. Persistit implements a "first updater wins" policy in which if two transactions attempt to update the same record, the first transaction "wins" by being allowed to continue, while the second transaction "loses" and is required to abort. |
3817 | + |
3818 | +Once a transaction has aborted, any subsequent database operation it attempts throws a ``RollbackException``. Application code should catch and handle this Exception. Usually the correct and desired behavior is simply to retry the transaction as shown in the code samples above. |
3819 | + |
3820 | +A transaction can also voluntarily roll back. For example, transaction logic could detect an error condition that it chooses to handle by throwing an exception back to the application. In this case the transaction should invoke the ``rollback`` method to explicitly declare its intent to abort the transaction. |
3821 | + |
3822 | +Read-Only Transactions |
3823 | +^^^^^^^^^^^^^^^^^^^^^^ |
3824 | + |
3825 | +Under Snapshot Isolation, transactions that read but do not modify data cannot generate any write-write dependencies and are therefore not subject to being rolled back because of the actions of other transactions. However, even though it modifies no data, a long-running read-only transaction can force Persistit to retain old value versions from other transactions for its duration in order to provide a snapshot view. This behavior can cause congestion and performance degradation by preventing very old values from being pruned. The degree to which this is a problem depends on the volume of update transactions being processed and the duration of long-running transactions. |
3826 | + |
3827 | +Snapshot Isolation is not Serializable |
3828 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
3829 | + |
3830 | +It is well-known that transactions executing under SI are not necessarily serializable. Under SI, so-called *write-skew* anomalies can happen with transactions that have certain kinds of interactions. Write-skew can be avoided by (a) explicit application-level locking or (b) structuring transactions to add write-write dependencies where write-skew otherwise could occur. |
3831 | + |
3832 | +Note that many common transaction patterns, including those defined by the TPC-C benchmark, do not experience write-skew and therefore *are* serializable under SI. |
3833 | + |
3834 | +Durability Options: ``CommitPolicy`` |
3835 | +------------------------------------ |
3836 | + |
3837 | +Persistit provides three policies that determine the durability of a transaction after it has executed the ``com.persistit.Transaction#commit`` method. These are: |
3838 | + |
3839 | + ``HARD`` |
3840 | + The ``commit`` method does not return until all updates created by the transaction have been written to non-volatile storage (e.g., disk storage). |
3841 | + ``GROUP`` |
3842 | + The ``commit`` method does not return until all updates created by the transaction have been written to non-volatile storage. In addition, the committing |
3843 | + transaction waits briefly in an attempt to recruit other transactions running in other threads to write their updates with the same physical I/O operation. |
3844 | + ``SOFT`` |
3845 | + The ``commit`` method returns *before* the updates have been recorded on non-volatile storage. Persistit attempts to write them within 100 milliseconds, but |
3846 | + this interval is not guaranteed. |
3847 | + |
3848 | +You can specify a default policy in the Persistit initialization properties using the ``txnpolicy`` property or under program control using ``com.persistit.Persistit#setDefaultTransactionCommitPolicy``. The default policy applies whenever the application calls the ``commit()`` method. You can override the default policy using ``commit(CommitPolicy)``. |
3849 | + |
3850 | +HARD and GROUP ensure each transaction is written durably to non-volatile storage before the ``commit`` method returns. The difference is that GROUP can improve throughput in multi-threaded applications because the average number of I/O operations needed to commit *N* transactions can be smaller than *N*. However, for one or a small number of concurrent threads, GROUP reduces throughput because it works by introducing a delay to allow other concurrent transactions to commit within a single I/O operation. |
3851 | + |
3852 | +SOFT commits are generally much faster than HARD or GROUP commits, especially for single-threaded applications, because the results of numerous transactions committed from a single thread can be aggregated and written to disk in a single I/O operation. However, transactions written with the SOFT commit policy are not immediately durable and it is possible that the recovered state of a database will be missing transactions that reported they were committed shortly before a crash. |
3853 | + |
3854 | +For SOFT commits, the state of the database after restart is such that for any committed transaction T, either all or none of its modifications will be present in the recovered database. Further, if a transaction T2 reads or updates data that was written by any other transaction T1, and if T2 is present in the recovered database, then so is T1. Any transaction that was in progress, but had not been committed at the time of the failure, is guaranteed not to be present in the recovered database. SOFT commits are designed to be durable within 100 milliseconds after ``commit`` returns. However, this interval is determined by computing the average duration of recent I/O operations to predict the completion time of the I/O that will write the transaction to disk, and therefore the interval cannot be guaranteed. |
3855 | + |
3856 | +Nested Transactions |
3857 | +------------------- |
3858 | + |
3859 | +A nested transaction occurs when code that is already executing within the scope of a transaction executes the ``begin`` method to start a new transaction. This might happen, for example, if an application’s transaction logic calls a method that also uses transactions. In this case, the commit processing of the inner transaction scope is deferred until the outermost transaction commits. At that point, all the updates performed within the inner and outer transaction scopes are committed to the database. Similarly, a rollback initiated by the inner transaction causes both it and the outermost transaction to roll back. |
3860 | + |
3861 | +Accumulators |
3862 | +------------ |
3863 | + |
3864 | +Consider an application in which concurrently running transactions share a counter. For example, suppose each transaction is responsible for allocating a unique integer as a primary key for a database record. One way to do this would be to store the counter in a Persistit key/value pair, reading the value at the start of each transaction and committing an update at the end. |
3865 | + |
3866 | +The problem with this approach is that under SI, concurrent transactions running in a multi-threaded application would experience very frequent write-write dependencies on the counter value; in fact, the only way to complete any transactions would be serially, one at a time. |
3867 | + |
3868 | +Persistit provides the ``com.persistit.Accumulator`` class to avoid this problem. An accumulator is designed to manage contributions from multiple concurrent transactions without causing write-write dependencies. Accumulators are durable in the sense that each transaction’s contribution is made durable with the transaction itself, and Persistit automatically recovers a correct state for each Accumulator in the event of a system crash. |
3869 | + |
3870 | +There are four types of accumulator in Persistit. Each a concrete subclass of the abstract ``com.persistit.Accumulator`` class: |
3871 | + |
3872 | + ``SUM`` |
3873 | + Tallies a count or sum of contributions by each transaction |
3874 | + ``MIN`` |
3875 | + Finds the minimum value contributed by all transactions |
3876 | + ``MAX`` |
3877 | + Finds the maximum value contributed by all transactions |
3878 | + ``SEQ`` |
3879 | + Special case of the SUM accumulator used to generate sequence numbers |
3880 | + |
3881 | +Accumulator instances are associated with a ``com.persistit.Tree``. Each ``Tree`` may have up to 64 accumulators. The following code fragment creates and/or acquires a ``SumAccumulator``, reads its snapshot value and then adds one to it: |
3882 | + |
3883 | +.. code-block:: java |
3884 | + |
3885 | + final Exchange ex = _persistit.getExchange(volume, treeName, true); |
3886 | + final Transaction txn = ex.getTransaction(); |
3887 | + txn.begin(); |
3888 | + try { |
3889 | + final Accumulator acc = |
3890 | + ex.getTree().getAccumulator(Accumulator.Type.SUM, 17); |
3891 | + long snap = acc.getSnapshotValue(txn); |
3892 | + acc.update(1, txn); |
3893 | + txn.commit(); |
3894 | + } finally { |
3895 | + txn.end(); |
3896 | + } |
3897 | + |
3898 | +The value 17 is simply an arbitrary index number between 0 and 63, inclusive. The application is responsible for allocating and managing accumulator indexes. |
3899 | + |
3900 | +The snapshot value of an accumulator obtained through ``com.persistit.Accumulator#getSnapshotValue()`` is the value computed from all updates contributed by transactions that had committed at the time the current transaction started, plus the transaction’s own as-yet uncommitted updates. In other words, the snapshot value of the accumulator is consistent with the snapshot view of all other data visible within the transaction. |
3901 | + |
3902 | +An accumulator has two ways of accessing its accumulated value: |
3903 | + |
3904 | + ``getSnapshotValue()`` |
3905 | + Is a value computed from updates that were committed at the start of the current transaction. This method may be called only within the scope of a |
3906 | + Transaction. |
3907 | + ``getLiveValue()`` |
3908 | + Is an ephemeral value reflecting all updates performed by all transactions, including concurrent and aborted transactions. |
3909 | + |
3910 | +The snapshot value is a precise, consistent tally, while the live value is approximate. For a ``SumAccumulator``, ``MaxAccumulator`` or ``SeqAccumulator``, if all updates are have non-negative arguments, then the live value is always greater than or equal to the snapshot value. |
3911 | + |
3912 | +SeqAccumulator |
3913 | +^^^^^^^^^^^^^^ |
3914 | + |
3915 | +The ``SeqAccumulator`` class has a special role in allocating unique identifier numbers, e.g., synthetic primary keys. The goal of the ``SeqAccumulator`` is to ensure that every committed transaction has received a unique value integer in all circumstances, including after recovery from a crash. See ``com.persistit.Accumulator`` for details. |
3916 | |
3917 | === removed file 'doc/Transactions.txt' |
3918 | --- doc/Transactions.txt 2012-04-30 22:09:31 +0000 |
3919 | +++ doc/Transactions.txt 1970-01-01 00:00:00 +0000 |
3920 | @@ -1,179 +0,0 @@ |
3921 | -[[Transactions]] |
3922 | -= Transactions |
3923 | - |
3924 | -Akiban Persistit supports transactions with multi-version concurrency control (MVCC) using a protocol called Snapshot Isolation (SI). An application calls +com.persistit.Transaction#begin+, +com.persistit.Transaction#commit+, +com.persistit.Transaction#rollback# and +com.persistit.Transaction#end+ methods to control the current transaction scope explicitly. A Transaction allows an application to execute multiple database operations in an atomic, consistent, isolated and durable (ACID) manner. |
3925 | - |
3926 | -Applications manage transactions through an instance of a +com.persistit.Transaction+ object. +Transaction+ does not represent a single transaction, but is instead a context in which a thread may perform many sequential transactions. The general pattern is that the application gets the current thread’s +Transaction+ instance, calls its +begin+ method, performs work, calls +commit+ and finally +end+. The thread uses the same +Transaction+ instance repeatedly. Generally each thread has one +Transaction+ that lasts for the entire life of the thread (but see com.persistit.Transaction#_threadManagement[Thread Management] for a mechanism that allows a transaction to be serviced by multiple threads). |
3927 | - |
3928 | -== Using Transactions |
3929 | - |
3930 | -The following code fragment performs two store operations within the scope of a transaction: |
3931 | - |
3932 | -[source,java] |
3933 | ----- |
3934 | -// |
3935 | -// Get the transaction context for the current thread. |
3936 | -// |
3937 | -Transaction txn = myExchange.getTransaction(); |
3938 | -int remainingRetries = RETRY_COUNT; |
3939 | -for (;;) { |
3940 | - txn.begin(); |
3941 | - try { |
3942 | - myExchange.getValue().put("First value"); |
3943 | - myExchange.clear().append(1).store(); |
3944 | - myExchange.getValue().put("Second value"); |
3945 | - myExchange.clear().append(2).store(); |
3946 | - // Required to commit the transaction |
3947 | - txn.commit(); |
3948 | - break; |
3949 | - } catch (RollbackException re) { |
3950 | - // perform any special rollback handling |
3951 | - // allow loop to repeat until commit succeeds or retries |
3952 | - // too many times. |
3953 | - if (--remainingRetries < 0) { |
3954 | - throw new TransactionFailedException(); |
3955 | - } |
3956 | - } catch (PersistitException pe) { |
3957 | - // handle other Persistit exception |
3958 | - } finally { |
3959 | - // Required to end the scope of a transaction. |
3960 | - txn.end(); |
3961 | - } |
3962 | -} |
3963 | ----- |
3964 | - |
3965 | -This example catches +com.persistit.exception.RollbackException+ which can be thrown by any Persistit operation within the scope of a transaction, including +commit+. Any code explicitly running within the scope of a transaction should be designed to handle rollbacks. |
3966 | - |
3967 | -This example also uses a _try/finally_ block to ensure every call to +begin+ has a matching call to +end+. This code pattern is mandatory: it is critical to correct transaction nesting behavior. |
3968 | - |
3969 | -One convenient way to do this is to encapsulate the logic of a transaction in an implementation of +com.persisitit.TransactionRunnable+ interface. The +com.persistit.Transaction#run+ method automatically provides logic to begin the transaction, execute the TransactionRunnable and commit the transaction, repeating the process until no rollback is thrown or a maximum retry count is reached. For example, the code fragment shown above can be rewritten as: |
3970 | - |
3971 | -[source,java] |
3972 | ----- |
3973 | -// |
3974 | -// Get the transaction context for the current thread. |
3975 | -// |
3976 | -Transaction txn = myExchange.getTransaction(); |
3977 | -// |
3978 | -// Perform the transaction with the following parameters: |
3979 | -// - try to commit it up to 10 times |
3980 | -// - delay 2 milliseconds before each retry |
3981 | -// - use the group commit durability policy |
3982 | -// |
3983 | -txn.run(new TransactionRunnable() { |
3984 | - public void run() throws PersistitException { |
3985 | - myExchange.getValue().put("First value"); |
3986 | - myExchange.clear().append(1).store(); |
3987 | - myExchange.getValue().put("Second value"); |
3988 | - myExchange.clear().append(2).store(); |
3989 | - } |
3990 | -}, 10, 2, CommitPolicy.GROUP); |
3991 | ----- |
3992 | - |
3993 | -=== Mixing Transactional and Non-Transactional Operations |
3994 | - |
3995 | -Database operations running outside the scope of an explicitly defined transaction are never subject to rollback and therefore do not require retry logic. However, such operations are also not guaranteed to be durable in the event of a system crash. Further, such operations are not isolated. Read operations performed outside of a transaction can read uncommitted updates, and updates performed outside of a transaction are visible within transactions. In other words, non-transactional reads and writes may break both the durability and isolation of concurrently executing transactions. Therefore it is strongly recommended that in an application that relies on transactions, all interactions with the database should use transactions. |
3996 | - |
3997 | -== Optimistic Transaction Scheduling |
3998 | - |
3999 | -To achieve high performance and scalability, Persistit supports an optimistic transaction scheduling protocol called MVCC with http://wikipedia.org/wiki/Snapshot_isolation[Snapshot Isolation]. Under this protocol multiple threads are permitted to execute transactions at full speed without blocking until a potentially inconsistent state is recognized. At that point a transaction suspected of causing the inconsistent state is automatically forced to roll back. |
4000 | - |
4001 | -Optimistic scheduling works because transactions usually do not collide, especially when individual database operations are fast, and so in practice transactions are seldom rolled back. But because any transaction may be rolled back at any point, applications must be designed carefully to avoid unintended side-effects. For example, a transaction should never perform non-repeatable or externally visible operations such as file or network I/O within its scope. |
4002 | - |
4003 | -=== Snapshot Isolation |
4004 | - |
4005 | -Persistit schedules concurrently executing transactions optimistically, without locking any database records. Instead, Persistit uses the well-known Snapshot Isolation protocol to achieve atomicity and isolation. While transactions are modifying data, Persistit maintains multiple versions of values being modified. Each version is labeled with the commit timestamp of the transaction that modified it. Whenever a transaction reads a value that has been modified by other transactions, it gets the latest version that was committed before its own start timestamp. In other words, all read operations are performed as if from a "snapshot" of the state of the database made at the transaction's start timestamp - hence the name "Snapshot Isolation." |
4006 | - |
4007 | -[[Pruning]] |
4008 | -=== Pruning |
4009 | - |
4010 | -Given that all updates written through transactions are created as versions within the MVCC scheme, a large number of versions can accumulate over time. Persistit reduces this proliferation through an activity called "pruning." Pruning resolves the final state of each version by removing any versions created by aborted transactions and removing obsolete versions no longer needed by other transactions. If a value contains only one version and the commit timestamp of the transaction that created it is before the start of any currently running transaction, that value is called _primordial_. The goal of pruning is to reduce most or all values in the database to their primordial states because updating and reading primordial values is more efficient than than managing multiple version values. Pruning happens automatically and is generally not visible to the application. |
4011 | - |
4012 | -=== Rollbacks |
4013 | - |
4014 | -Usually Snapshot Isolation allows concurrent transactions to commit without interference but this is not always the case. Two concurrent transactions that attempt to modify the same Persistit key/value pair before they commit are said to have a "write-write dependency". To avoid anomalous results one of them must abort, rolling back any other updates it may also have created, and retry. Persistit implements a "first updater wins" policy in which if two transactions attempt to update the same record, the first transaction "wins" by being allowed to continue, while the second transaction "loses" and is required to abort. |
4015 | - |
4016 | -Once a transaction has aborted, any subsequent database operation it attempts throws a +RollbackException+. Application code should catch and handle this Exception. Usually the correct and desired behavior is simply to retry the transaction as shown in the code samples above. |
4017 | - |
4018 | -A transaction can also voluntarily roll back. For example, transaction logic could detect an error condition that it chooses to handle by throwing an exception back to the application. In this case the transaction should invoke the +rollback+ method to explicitly declare its intent to abort the transaction. |
4019 | - |
4020 | -=== Read-Only Transactions |
4021 | - |
4022 | -Under Snapshot Isolation, transactions that read but do not modify data cannot generate any write-write dependencies and are therefore not subject to being rolled back because of the actions of other transactions. However, even though it modifies no data, a long-running read-only transaction can force Persistit to retain old value versions from other transactions for its duration in order to provide a snapshot view. This behavior can cause congestion and performance degradation by preventing very old values from being pruned. The degree to which this is a problem depends on the volume of update transactions being processed and the duration of long-running transactions. |
4023 | - |
4024 | -=== Snapshot Isolation is not Serializable |
4025 | - |
4026 | -It is well-known that transactions executing under SI are not necessarily serializable. Under SI, so-called _write-skew_ anomalies can happen with transactions that have certain kinds of interactions. Write-skew can be avoided by (a) explicit application-level locking or (b) structuring transactions to add write-write dependencies where write-skew otherwise could occur. |
4027 | - |
4028 | -Note that many common transaction patterns, including those defined by the TPC-C benchmark, do not experience write-skew and therefore _are_ serializable under SI. |
4029 | - |
4030 | -== Durability Options: +CommitPolicy+ |
4031 | - |
4032 | -Persistit provides three policies that determine the durability of a transaction after it has executed the +com.persistit.Transaction#commit+ method. These are: |
4033 | - |
4034 | -[horizontal] |
4035 | -+HARD+:: The +commit+ method does not return until all updates created by the transaction have been written to non-volatile storage (e.g., disk storage). |
4036 | -+GROUP+:: The +commit+ method does not return until all updates created by the transaction have been written to non-volatile storage. In addition, the committing transaction waits briefly in an attempt to recruit other transactions running in other threads to write their updates with the same physical I/O operation. |
4037 | -+SOFT+:: The +commit+ method returns _before_ the updates have been recorded on non-volatile storage. Persistit attempts to write them within 100 milliseconds, but this interval is not guaranteed. |
4038 | - |
4039 | -You can specify a default policy in the Persistit initialization properties using the +txnpolicy+ property or under program control using +com.persistit.Persistit#setDefaultTransactionCommitPolicy+. The default policy applies whenever the application calls the +commit()+ method. You can override the default policy using +commit(CommitPolicy)+. |
4040 | - |
4041 | -HARD and GROUP ensure each transaction is written durably to non-volatile storage before the +commit+ method returns. The difference is that GROUP can improve throughput in multi-threaded applications because the average number of I/O operations needed to commit _N_ transactions can be smaller than _N_. However, for one or a small number of concurrent threads, GROUP reduces throughput because it works by introducing a delay to allow other concurrent transactions to commit within a single I/O operation. |
4042 | - |
4043 | -SOFT commits are generally much faster than HARD or GROUP commits, especially for single-threaded applications, because the results of numerous transactions committed from a single thread can be aggregated and written to disk in a single I/O operation. However, transactions written with the SOFT commit policy are not immediately durable and it is possible that the recovered state of a database will be missing transactions that reported they were committed shortly before a crash. |
4044 | - |
4045 | -For SOFT commits, the state of the database after restart is such that for any committed transaction T, either all or none of its modifications will be present in the recovered database. Further, if a transaction T2 reads or updates data that was written by any other transaction T1, and if T2 is present in the recovered database, then so is T1. Any transaction that was in progress, but had not been committed at the time of the failure, is guaranteed not to be present in the recovered database. SOFT commits are designed to be durable within 100 milliseconds after +commit+ returns. However, this interval is determined by computing the average duration of recent I/O operations to predict the completion time of the I/O that will write the transaction to disk, and therefore the interval cannot be guaranteed. |
4046 | - |
4047 | -== Nested Transactions |
4048 | - |
4049 | -A nested transaction occurs when code that is already executing within the scope of a transaction executes the +begin+ method to start a new transaction. This might happen, for example, if an application’s transaction logic calls a method that also uses transactions. In this case, the commit processing of the inner transaction scope is deferred until the outermost transaction commits. At that point, all the updates performed within the inner and outer transaction scopes are committed to the database. Similarly, a rollback initiated by the inner transaction causes both it and the outermost transaction to roll back. |
4050 | - |
4051 | -== Accumulators |
4052 | - |
4053 | -Consider an application in which concurrently running transactions share a counter. For example, suppose each transaction is responsible for allocating a unique integer as a primary key for a database record. One way to do this would be to store the counter in a Persistit key/value pair, reading the value at the start of each transaction and committing an update at the end. |
4054 | - |
4055 | -The problem with this approach is that under SI, concurrent transactions running in a multi-threaded application would experience very frequent write-write dependencies on the counter value; in fact, the only way to complete any transactions would be serially, one at a time. |
4056 | - |
4057 | -Persistit provides the +com.persistit.Accumulator+ class to avoid this problem. An accumulator is designed to manage contributions from multiple concurrent transactions without causing write-write dependencies. Accumulators are durable in the sense that each transaction’s contribution is made durable with the transaction itself, and Persistit automatically recovers a correct state for each Accumulator in the event of a system crash. |
4058 | - |
4059 | -There are four types of accumulator in Persistit. Each a concrete subclass of the abstract +com.persistit.Accumulator+ class: |
4060 | - |
4061 | -[horizontal] |
4062 | -+SUM+:: Tallies a count or sum of contributions by each transaction |
4063 | -+MIN+:: Finds the minimum value contributed by all transactions |
4064 | -+MAX+:: Finds the maximum value contributed by all transactions |
4065 | -+SEQ+:: Special case of the SUM accumulator used to generate sequence numbers |
4066 | - |
4067 | -Accumulator instances are associated with a +com.persistit.Tree+. Each +Tree+ may have up to 64 accumulators. The following code fragment creates and/or acquires a +SumAccumulator+, reads its snapshot value and then adds one to it: |
4068 | - |
4069 | -[source,java] |
4070 | ----- |
4071 | -final Exchange ex = _persistit.getExchange(volume, treeName, true); |
4072 | -final Transaction txn = ex.getTransaction(); |
4073 | -txn.begin(); |
4074 | -try { |
4075 | - final Accumulator acc = |
4076 | - ex.getTree().getAccumulator(Accumulator.Type.SUM, 17); |
4077 | - long snap = acc.getSnapshotValue(txn); |
4078 | - acc.update(1, txn); |
4079 | - txn.commit(); |
4080 | -} finally { |
4081 | - txn.end(); |
4082 | -} |
4083 | ----- |
4084 | - |
4085 | -The value 17 is simply an arbitrary index number between 0 and 63, inclusive. The application is responsible for allocating and managing accumulator indexes. |
4086 | - |
4087 | -The snapshot value of an accumulator obtained through +com.persistit.Accumulator#getSnapshotValue()+ is the value computed from all updates contributed by transactions that had committed at the time the current transaction started, plus the transaction’s own as-yet uncommitted updates. In other words, the snapshot value of the accumulator is consistent with the snapshot view of all other data visible within the transaction. |
4088 | - |
4089 | -An accumulator has two ways of accessing its accumulated value: |
4090 | - |
4091 | -[horizontal] |
4092 | -+getSnapshotValue()+:: Is a value computed from updates that were committed at the start of the current transaction. This method may be called only within the scope of a Transaction. |
4093 | -+getLiveValue()+:: Is an ephemeral value reflecting all updates performed by all transactions, including concurrent and aborted transactions. |
4094 | - |
4095 | -The snapshot value is a precise, consistent tally, while the live value is approximate. For a +SumAccumulator+, +MaxAccumulator+ or +SeqAccumulator+, if all updates are have non-negative arguments, then the live value is always greater than or equal to the snapshot value. |
4096 | - |
4097 | -=== SeqAccumulator |
4098 | - |
4099 | -The +SeqAccumulator+ class has a special role in allocating unique identifier numbers, e.g., synthetic primary keys. The goal of the +SeqAccumulator+ is to ensure that every committed transaction has received a unique value integer in all circumstances, including after recovery from a crash. See +com.persistit.Accumulator+ for details. |
4100 | |
4101 | === modified file 'doc/build/build-doc.sh' |
4102 | --- doc/build/build-doc.sh 2012-05-25 18:50:59 +0000 |
4103 | +++ doc/build/build-doc.sh 2012-05-30 18:23:19 +0000 |
4104 | @@ -37,12 +37,29 @@ |
4105 | # The end-product files, user_guide.html and user_guide.xml are written |
4106 | # there. |
4107 | # |
4108 | -rm -rf /tmp/akiban-persistit-doc |
4109 | -mkdir /tmp/akiban-persistit-doc |
4110 | -javac -d /tmp/akiban-persistit-doc -cp ../../core/target/classes/ src/*.java |
4111 | -java -cp /tmp/akiban-persistit-doc:../../core/target/classes AsciiDocPrep in=../TOC.txt out=/tmp/akiban-persistit-doc/doc.txt base=apidocs index=../../core/target/site/apidocs/index-all.html |
4112 | -asciidoc -a toc -n -d book -b xhtml11 -o /tmp/akiban-persistit-doc/doc.html /tmp/akiban-persistit-doc/doc.txt |
4113 | -asciidoc -a toc -n -d book -b docbook -o /tmp/akiban-persistit-doc/doc.xml /tmp/akiban-persistit-doc/doc.txt |
4114 | -sed s/\`/\ / /tmp/akiban-persistit-doc/doc.html > /tmp/akiban-persistit-doc/user_guide.html |
4115 | -sed s/\`/\ / /tmp/akiban-persistit-doc/doc.xml > /tmp/akiban-persistit-doc/user_guide.xml |
4116 | +rm -rf ../../target/sphinx/source |
4117 | +mkdir -p ../../target/sphinx/source |
4118 | +mkdir -p ../../target/sphinx/classes |
4119 | +mkdir -p ../../target/sphinx/html |
4120 | +mkdir -p ../../target/sphinx/text |
4121 | + |
4122 | +cp ../index.rst ../../target/sphinx/source |
4123 | +cp ../conf.py ../../target/sphinx/source |
4124 | + |
4125 | +javac -d ../../target/sphinx/classes -cp ../../target/classes/ src/*.java |
4126 | + |
4127 | +java -cp ../../target/sphinx/classes:../../target/classes SphinxDocPrep in=../ReleaseNotes.rst out=../../target/sphinx/source/ReleaseNotes.rst base=http://www.akiban.com/ak-docs/admin/persistit/apidocs index=../../target/site/apidocs/index-all.html |
4128 | +java -cp ../../target/sphinx/classes:../../target/classes SphinxDocPrep in=../BasicAPI.rst out=../../target/sphinx/source/BasicAPI.rst base=http://www.akiban.com/ak-docs/admin/persistit/apidocs index=../../target/site/apidocs/index-all.html |
4129 | +java -cp ../../target/sphinx/classes:../../target/classes SphinxDocPrep in=../Configuration.rst out=../../target/sphinx/source/Configuration.rst base=http://www.akiban.com/ak-docs/admin/persistit/apidocs index=../../target/site/apidocs/index-all.html |
4130 | +java -cp ../../target/sphinx/classes:../../target/classes SphinxDocPrep in=../GettingStarted.rst out=../../target/sphinx/source/GettingStarted.rst base=http://www.akiban.com/ak-docs/admin/persistit/apidocs index=../../target/site/apidocs/index-all.html |
4131 | +java -cp ../../target/sphinx/classes:../../target/classes SphinxDocPrep in=../Management.rst out=../../target/sphinx/source/Management.rst base=http://www.akiban.com/ak-docs/admin/persistit/apidocs index=../../target/site/apidocs/index-all.html |
4132 | +java -cp ../../target/sphinx/classes:../../target/classes SphinxDocPrep in=../Miscellaneous.rst out=../../target/sphinx/source/Miscellaneous.rst base=http://www.akiban.com/ak-docs/admin/persistit/apidocs index=../../target/site/apidocs/index-all.html |
4133 | +java -cp ../../target/sphinx/classes:../../target/classes SphinxDocPrep in=../PhysicalStorage.rst out=../../target/sphinx/source/PhysicalStorage.rst base=http://www.akiban.com/ak-docs/admin/persistit/apidocs index=../../target/site/apidocs/index-all.html |
4134 | +java -cp ../../target/sphinx/classes:../../target/classes SphinxDocPrep in=../Security.rst out=../../target/sphinx/source/Security.rst base=http://www.akiban.com/ak-docs/admin/persistit/apidocs index=../../target/site/apidocs/index-all.html |
4135 | +java -cp ../../target/sphinx/classes:../../target/classes SphinxDocPrep in=../Serialization.rst out=../../target/sphinx/source/Serialization.rst base=http://www.akiban.com/ak-docs/admin/persistit/apidocs index=../../target/site/apidocs/index-all.html |
4136 | +java -cp ../../target/sphinx/classes:../../target/classes SphinxDocPrep in=../Transactions.rst out=../../target/sphinx/source/Transactions.rst base=http://www.akiban.com/ak-docs/admin/persistit/apidocs index=../../target/site/apidocs/index-all.html |
4137 | + |
4138 | +sphinx-build -a ../../target/sphinx/source ../../target/sphinx/html |
4139 | + |
4140 | +fold -s ../../target/sphinx/source/ReleaseNotes.rst | sed 's/``//g' | sed 's/\.\. note:/NOTE/' | sed 's/::/:/' > ../../target/sphinx/text/ReleaseNotes |
4141 | |
4142 | |
4143 | === added file 'doc/build/build-doc.sh.orig' |
4144 | --- doc/build/build-doc.sh.orig 1970-01-01 00:00:00 +0000 |
4145 | +++ doc/build/build-doc.sh.orig 2012-05-30 18:23:19 +0000 |
4146 | @@ -0,0 +1,48 @@ |
4147 | +#/bin/sh |
4148 | +# |
4149 | +# Copyright © 2011-2012 Akiban Technologies, Inc. All rights reserved. |
4150 | +# |
4151 | +# This program is free software: you can redistribute it and/or modify |
4152 | +# it under the terms of the GNU Affero General Public License as |
4153 | +# published by the Free Software Foundation, version 3 (only) of the |
4154 | +# License. |
4155 | +# |
4156 | +# This program is distributed in the hope that it will be useful, |
4157 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
4158 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4159 | +# GNU Affero General Public License for more details. |
4160 | +# |
4161 | +# You should have received a copy of the GNU Affero General Public License |
4162 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
4163 | +# |
4164 | +# This program may also be available under different license terms. For more |
4165 | +# information, see www.akiban.com or contact licensing@akiban.com. |
4166 | +# |
4167 | + |
4168 | +# --------------------- |
4169 | +# |
4170 | +# Builds the Akiban Persistit doc set. Currently this process is based on |
4171 | +# the asciidoc tool (http://www.methods.co.nz/asciidoc/). |
4172 | +# |
4173 | +# Here are the steps: |
4174 | +# 1. Run a Java program AsciiDocPrep to prepare a text asciidoc file. |
4175 | +# Among other things, AsciiDocPrep fills in JavaDoc hyperlinks. |
4176 | +# 2. Run asciidoc to generate an html file. |
4177 | +# 3. Use sed to replace some characters. Turns out asciidoc doesn't like |
4178 | +# to link to URLs having spaces, so AsciDocPrep replaces those spaces |
4179 | +# with the "`" character. This step converts those back to spaces. |
4180 | +# |
4181 | +# Run this script from the root of the persistit source directory. This |
4182 | +# script writes changes only into a directory /tmp/akiban-persistit-doc. |
4183 | +# The end-product files, user_guide.html and user_guide.xml are written |
4184 | +# there. |
4185 | +# |
4186 | +rm -rf /tmp/akiban-persistit-doc |
4187 | +mkdir /tmp/akiban-persistit-doc |
4188 | +javac -d /tmp/akiban-persistit-doc -cp ../../core/target/classes/ src/*.java |
4189 | +java -cp /tmp/akiban-persistit-doc:../../core/target/classes AsciiDocPrep in=../TOC.txt out=/tmp/akiban-persistit-doc/doc.txt base=apidocs index=../../core/target/site/apidocs/index-all.html |
4190 | +asciidoc -a toc -n -d book -b xhtml11 -o /tmp/akiban-persistit-doc/doc.html /tmp/akiban-persistit-doc/doc.txt |
4191 | +asciidoc -a toc -n -d book -b docbook -o /tmp/akiban-persistit-doc/doc.xml /tmp/akiban-persistit-doc/doc.txt |
4192 | +sed s/\`/\ / /tmp/akiban-persistit-doc/doc.html > /tmp/akiban-persistit-doc/user_guide.html |
4193 | +sed s/\`/\ / /tmp/akiban-persistit-doc/doc.xml > /tmp/akiban-persistit-doc/user_guide.xml |
4194 | + |
4195 | |
4196 | === added file 'doc/build/src/SphinxDocPrep.java' |
4197 | --- doc/build/src/SphinxDocPrep.java 1970-01-01 00:00:00 +0000 |
4198 | +++ doc/build/src/SphinxDocPrep.java 2012-05-30 18:23:19 +0000 |
4199 | @@ -0,0 +1,147 @@ |
4200 | +import java.io.BufferedReader; |
4201 | +import java.io.File; |
4202 | +import java.io.FileReader; |
4203 | +import java.io.FileWriter; |
4204 | +import java.io.PrintWriter; |
4205 | +import java.util.SortedMap; |
4206 | +import java.util.regex.Matcher; |
4207 | +import java.util.regex.Pattern; |
4208 | + |
4209 | +import com.persistit.util.ArgParser; |
4210 | + |
4211 | +public class SphinxDocPrep { |
4212 | + |
4213 | + private final static Pattern PERSISTIT_PATTERN = Pattern |
4214 | + .compile("(``)?(com\\.persistit(?:\\.[a-z]\\w*)*(?:\\.[A-Z]\\w*)+)(?:#(\\w+(?:[\\(\\)\\,a-zA-Z]*)))?(``)?"); |
4215 | + |
4216 | + private final static String[] ARG_TEMPLATE = { "in|string:|Input file", "out|string:|Output file", |
4217 | + "index|string:|Pathname of index-all.html file", "base|string:|Base of generated URLs", }; |
4218 | + |
4219 | + enum BlockState { |
4220 | + OUT, WAIT_FIRST_BLANK_LINE, WAIT_SECOND_BLANK_LINE |
4221 | + } |
4222 | + |
4223 | + private AsciiDocIndex index; |
4224 | + private BlockState block = BlockState.OUT; |
4225 | + private PrintWriter writer; |
4226 | + private String base; |
4227 | + private String indexPath; |
4228 | + |
4229 | + private void prepare(final String[] args) throws Exception { |
4230 | + ArgParser ap = new ArgParser("SphinxDocPrep", args, ARG_TEMPLATE); |
4231 | + final String inPath = ap.getStringValue("in"); |
4232 | + final String outPath = ap.getStringValue("out"); |
4233 | + |
4234 | + writer = outPath.isEmpty() ? new PrintWriter(System.out) : new PrintWriter(new FileWriter(outPath)); |
4235 | + |
4236 | + base = ap.getStringValue("base"); |
4237 | + if (base.isEmpty()) { |
4238 | + base = "http://akiban.com/persistit/doc/apidocs"; |
4239 | + } |
4240 | + indexPath = ap.getStringValue("index"); |
4241 | + if (indexPath.isEmpty()) { |
4242 | + indexPath = "/home/peter/website/apidocs/index-all.html"; |
4243 | + } |
4244 | + |
4245 | + index = new AsciiDocIndex(); |
4246 | + System.out.print("Building JavaDoc index.."); |
4247 | + index.buildIndex(indexPath, base); |
4248 | + System.out.println("done"); |
4249 | + |
4250 | + processFile(new File(inPath), 0); |
4251 | + writer.close(); |
4252 | + } |
4253 | + |
4254 | + public void processFile(final File file, final int level) throws Exception { |
4255 | + BufferedReader reader = new BufferedReader(new FileReader(file)); |
4256 | + System.out.print("Processing file " + file); |
4257 | + String line; |
4258 | + while ((line = reader.readLine()) != null) { |
4259 | + if (line.startsWith("@")) { |
4260 | + processFile(new File(file.getParentFile(), line.substring(1)), level + 1); |
4261 | + } else { |
4262 | + processLine(line); |
4263 | + } |
4264 | + } |
4265 | + writer.println(); |
4266 | + System.out.println(" - done"); |
4267 | + } |
4268 | + |
4269 | + private void processLine(final String line) throws Exception { |
4270 | + if (line.contains(".. code-block:")) { |
4271 | + block = BlockState.WAIT_FIRST_BLANK_LINE; |
4272 | + } else if (line.isEmpty()) { |
4273 | + switch (block) { |
4274 | + case WAIT_FIRST_BLANK_LINE: |
4275 | + block = BlockState.WAIT_SECOND_BLANK_LINE; |
4276 | + break; |
4277 | + |
4278 | + case WAIT_SECOND_BLANK_LINE: |
4279 | + block = BlockState.OUT; |
4280 | + break; |
4281 | + |
4282 | + default: |
4283 | + // no change |
4284 | + } |
4285 | + } |
4286 | + |
4287 | + if (block == BlockState.OUT) { |
4288 | + final StringBuffer sb = new StringBuffer(); |
4289 | + if (line.startsWith("=")) { |
4290 | + sb.append("="); |
4291 | + } |
4292 | + final Matcher matcher = PERSISTIT_PATTERN.matcher(line); |
4293 | + while (matcher.find()) { |
4294 | + processMatch(matcher, sb); |
4295 | + } |
4296 | + matcher.appendTail(sb); |
4297 | + writer.println(sb.toString()); |
4298 | + } else { |
4299 | + writer.println(line); |
4300 | + writer.flush(); |
4301 | + } |
4302 | + } |
4303 | + |
4304 | + private void processMatch(final Matcher matcher, final StringBuffer sb) { |
4305 | + String className = matcher.group(2); |
4306 | + String methodName = matcher.group(3); |
4307 | + |
4308 | + String replacement; |
4309 | + if (methodName == null) { |
4310 | + String url = index.getClassMap().get(className); |
4311 | + if (url == null || url.isEmpty()) { |
4312 | + replacement = "<<<Missing class: " + className + ">>>"; |
4313 | + } else { |
4314 | + replacement = "`" + className + " <" + url + ">`_"; |
4315 | + } |
4316 | + } else { |
4317 | + String from = className + "#" + methodName.split("\\(")[0]; |
4318 | + final SortedMap<String, String> map = index.getMethodMap().tailMap(from); |
4319 | + String url; |
4320 | + if (map.isEmpty()) { |
4321 | + replacement = "<<<Missing method: " + methodName + ">>>"; |
4322 | + } else { |
4323 | + final String first = map.firstKey(); |
4324 | + url = map.get(first); |
4325 | + url = url.replace(" ", "%20"); |
4326 | + String text = first.split("#")[1]; |
4327 | + text = text.replace("com.persistit.encoding.", ""); |
4328 | + text = text.replace("com.persistit.exception.", ""); |
4329 | + text = text.replace("com.persistit.logging.", ""); |
4330 | + text = text.replace("com.persistit.mxbeans.", ""); |
4331 | + text = text.replace("com.persistit.ref.", ""); |
4332 | + text = text.replace("com.persistit.ui.", ""); |
4333 | + text = text.replace("com.persistit.", ""); |
4334 | + text = text.replace("java.lang.", ""); |
4335 | + text = text.replace("java.util.", ""); |
4336 | + replacement= "`" + text + " <" + url + ">`_"; |
4337 | + } |
4338 | + } |
4339 | + |
4340 | + matcher.appendReplacement(sb, Matcher.quoteReplacement(replacement)); |
4341 | + } |
4342 | + |
4343 | + public static void main(final String[] args) throws Exception { |
4344 | + new SphinxDocPrep().prepare(args); |
4345 | + } |
4346 | +} |
4347 | |
4348 | === added file 'doc/conf.py' |
4349 | --- doc/conf.py 1970-01-01 00:00:00 +0000 |
4350 | +++ doc/conf.py 2012-05-30 18:23:19 +0000 |
4351 | @@ -0,0 +1,285 @@ |
4352 | +# -*- coding: utf-8 -*- |
4353 | +# |
4354 | +# PersistitDoc documentation build configuration file, created by |
4355 | +# sphinx-quickstart on Fri May 18 15:19:04 2012. |
4356 | +# |
4357 | +# This file is execfile()d with the current directory set to its containing dir. |
4358 | +# |
4359 | +# Note that not all possible configuration values are present in this |
4360 | +# autogenerated file. |
4361 | +# |
4362 | +# All configuration values have a default; values that are commented out |
4363 | +# serve to show the default. |
4364 | + |
4365 | +import sys, os |
4366 | + |
4367 | +# If extensions (or modules to document with autodoc) are in another directory, |
4368 | +# add these directories to sys.path here. If the directory is relative to the |
4369 | +# documentation root, use os.path.abspath to make it absolute, like shown here. |
4370 | +#sys.path.insert(0, os.path.abspath('.')) |
4371 | + |
4372 | +# -- General configuration ----------------------------------------------------- |
4373 | + |
4374 | +# If your documentation needs a minimal Sphinx version, state it here. |
4375 | +#needs_sphinx = '1.0' |
4376 | + |
4377 | +# Add any Sphinx extension module names here, as strings. They can be extensions |
4378 | +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. |
4379 | +extensions = ['sphinx.ext.todo'] |
4380 | + |
4381 | +# Add any paths that contain templates here, relative to this directory. |
4382 | +templates_path = ['_templates'] |
4383 | + |
4384 | +# The suffix of source filenames. |
4385 | +source_suffix = '.rst' |
4386 | + |
4387 | +# The encoding of source files. |
4388 | +#source_encoding = 'utf-8-sig' |
4389 | + |
4390 | +# The master toctree document. |
4391 | +master_doc = 'index' |
4392 | + |
4393 | +# General information about the project. |
4394 | +project = u'PersistitDoc' |
4395 | +copyright = u'2012, Akiban Technologies' |
4396 | + |
4397 | +# The version info for the project you're documenting, acts as replacement for |
4398 | +# |version| and |release|, also used in various other places throughout the |
4399 | +# built documents. |
4400 | +# |
4401 | +# The short X.Y version. |
4402 | +version = '1' |
4403 | +# The full version, including alpha/beta/rc tags. |
4404 | +release = '1' |
4405 | + |
4406 | +# The language for content autogenerated by Sphinx. Refer to documentation |
4407 | +# for a list of supported languages. |
4408 | +#language = None |
4409 | + |
4410 | +# There are two options for replacing |today|: either, you set today to some |
4411 | +# non-false value, then it is used: |
4412 | +#today = '' |
4413 | +# Else, today_fmt is used as the format for a strftime call. |
4414 | +#today_fmt = '%B %d, %Y' |
4415 | + |
4416 | +# List of patterns, relative to source directory, that match files and |
4417 | +# directories to ignore when looking for source files. |
4418 | +exclude_patterns = [] |
4419 | + |
4420 | +# The reST default role (used for this markup: `text`) to use for all documents. |
4421 | +#default_role = None |
4422 | + |
4423 | +# If true, '()' will be appended to :func: etc. cross-reference text. |
4424 | +#add_function_parentheses = True |
4425 | + |
4426 | +# If true, the current module name will be prepended to all description |
4427 | +# unit titles (such as .. function::). |
4428 | +#add_module_names = True |
4429 | + |
4430 | +# If true, sectionauthor and moduleauthor directives will be shown in the |
4431 | +# output. They are ignored by default. |
4432 | +#show_authors = False |
4433 | + |
4434 | +# The name of the Pygments (syntax highlighting) style to use. |
4435 | +pygments_style = 'sphinx' |
4436 | + |
4437 | +# A list of ignored prefixes for module index sorting. |
4438 | +#modindex_common_prefix = [] |
4439 | + |
4440 | + |
4441 | +# -- Options for HTML output --------------------------------------------------- |
4442 | + |
4443 | +# The theme to use for HTML and HTML Help pages. See the documentation for |
4444 | +# a list of builtin themes. |
4445 | +html_theme = 'default' |
4446 | + |
4447 | +# Theme options are theme-specific and customize the look and feel of a theme |
4448 | +# further. For a list of options available for each theme, see the |
4449 | +# documentation. |
4450 | +#html_theme_options = {} |
4451 | + |
4452 | +# Add any paths that contain custom themes here, relative to this directory. |
4453 | +#html_theme_path = [] |
4454 | + |
4455 | +# The name for this set of Sphinx documents. If None, it defaults to |
4456 | +# "<project> v<release> documentation". |
4457 | +#html_title = None |
4458 | + |
4459 | +# A shorter title for the navigation bar. Default is the same as html_title. |
4460 | +#html_short_title = None |
4461 | + |
4462 | +# The name of an image file (relative to this directory) to place at the top |
4463 | +# of the sidebar. |
4464 | +#html_logo = None |
4465 | + |
4466 | +# The name of an image file (within the static path) to use as favicon of the |
4467 | +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 |
4468 | +# pixels large. |
4469 | +#html_favicon = None |
4470 | + |
4471 | +# Add any paths that contain custom static files (such as style sheets) here, |
4472 | +# relative to this directory. They are copied after the builtin static files, |
4473 | +# so a file named "default.css" will overwrite the builtin "default.css". |
4474 | +html_static_path = ['_static'] |
4475 | + |
4476 | +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, |
4477 | +# using the given strftime format. |
4478 | +#html_last_updated_fmt = '%b %d, %Y' |
4479 | + |
4480 | +# If true, SmartyPants will be used to convert quotes and dashes to |
4481 | +# typographically correct entities. |
4482 | +#html_use_smartypants = True |
4483 | + |
4484 | +# Custom sidebar templates, maps document names to template names. |
4485 | +#html_sidebars = {} |
4486 | + |
4487 | +# Additional templates that should be rendered to pages, maps page names to |
4488 | +# template names. |
4489 | +#html_additional_pages = {} |
4490 | + |
4491 | +# If false, no module index is generated. |
4492 | +#html_domain_indices = True |
4493 | + |
4494 | +# If false, no index is generated. |
4495 | +#html_use_index = True |
4496 | + |
4497 | +# If true, the index is split into individual pages for each letter. |
4498 | +#html_split_index = False |
4499 | + |
4500 | +# If true, links to the reST sources are added to the pages. |
4501 | +#html_show_sourcelink = True |
4502 | + |
4503 | +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. |
4504 | +#html_show_sphinx = True |
4505 | + |
4506 | +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. |
4507 | +#html_show_copyright = True |
4508 | + |
4509 | +# If true, an OpenSearch description file will be output, and all pages will |
4510 | +# contain a <link> tag referring to it. The value of this option must be the |
4511 | +# base URL from which the finished HTML is served. |
4512 | +#html_use_opensearch = '' |
4513 | + |
4514 | +# This is the file name suffix for HTML files (e.g. ".xhtml"). |
4515 | +#html_file_suffix = None |
4516 | + |
4517 | +# Output file base name for HTML help builder. |
4518 | +htmlhelp_basename = 'PersistitDocdoc' |
4519 | + |
4520 | + |
4521 | +# -- Options for LaTeX output -------------------------------------------------- |
4522 | + |
4523 | +latex_elements = { |
4524 | +# The paper size ('letterpaper' or 'a4paper'). |
4525 | +#'papersize': 'letterpaper', |
4526 | + |
4527 | +# The font size ('10pt', '11pt' or '12pt'). |
4528 | +#'pointsize': '10pt', |
4529 | + |
4530 | +# Additional stuff for the LaTeX preamble. |
4531 | +#'preamble': '', |
4532 | +} |
4533 | + |
4534 | +# Grouping the document tree into LaTeX files. List of tuples |
4535 | +# (source start file, target name, title, author, documentclass [howto/manual]). |
4536 | +latex_documents = [ |
4537 | + ('index', 'PersistitDoc.tex', u'PersistitDoc Documentation', |
4538 | + u'Akiban Technologies', 'manual'), |
4539 | +] |
4540 | + |
4541 | +# The name of an image file (relative to this directory) to place at the top of |
4542 | +# the title page. |
4543 | +#latex_logo = None |
4544 | + |
4545 | +# For "manual" documents, if this is true, then toplevel headings are parts, |
4546 | +# not chapters. |
4547 | +#latex_use_parts = False |
4548 | + |
4549 | +# If true, show page references after internal links. |
4550 | +#latex_show_pagerefs = False |
4551 | + |
4552 | +# If true, show URL addresses after external links. |
4553 | +#latex_show_urls = False |
4554 | + |
4555 | +# Documents to append as an appendix to all manuals. |
4556 | +#latex_appendices = [] |
4557 | + |
4558 | +# If false, no module index is generated. |
4559 | +#latex_domain_indices = True |
4560 | + |
4561 | + |
4562 | +# -- Options for manual page output -------------------------------------------- |
4563 | + |
4564 | +# One entry per manual page. List of tuples |
4565 | +# (source start file, name, description, authors, manual section). |
4566 | +man_pages = [ |
4567 | + ('index', 'persistitdoc', u'PersistitDoc Documentation', |
4568 | + [u'Akiban Technologies'], 1) |
4569 | +] |
4570 | + |
4571 | +# If true, show URL addresses after external links. |
4572 | +#man_show_urls = False |
4573 | + |
4574 | + |
4575 | +# -- Options for Texinfo output ------------------------------------------------ |
4576 | + |
4577 | +# Grouping the document tree into Texinfo files. List of tuples |
4578 | +# (source start file, target name, title, author, |
4579 | +# dir menu entry, description, category) |
4580 | +texinfo_documents = [ |
4581 | + ('index', 'PersistitDoc', u'PersistitDoc Documentation', |
4582 | + u'Akiban Technologies', 'PersistitDoc', 'One line description of project.', |
4583 | + 'Miscellaneous'), |
4584 | +] |
4585 | + |
4586 | +# Documents to append as an appendix to all manuals. |
4587 | +#texinfo_appendices = [] |
4588 | + |
4589 | +# If false, no module index is generated. |
4590 | +#texinfo_domain_indices = True |
4591 | + |
4592 | +# How to display URL addresses: 'footnote', 'no', or 'inline'. |
4593 | +#texinfo_show_urls = 'footnote' |
4594 | + |
4595 | + |
4596 | +# -- Options for Epub output --------------------------------------------------- |
4597 | + |
4598 | +# Bibliographic Dublin Core info. |
4599 | +epub_title = u'PersistitDoc' |
4600 | +epub_author = u'Akiban Technologies' |
4601 | +epub_publisher = u'Akiban Technologies' |
4602 | +epub_copyright = u'2012, Akiban Technologies' |
4603 | + |
4604 | +# The language of the text. It defaults to the language option |
4605 | +# or en if the language is not set. |
4606 | +#epub_language = '' |
4607 | + |
4608 | +# The scheme of the identifier. Typical schemes are ISBN or URL. |
4609 | +#epub_scheme = '' |
4610 | + |
4611 | +# The unique identifier of the text. This can be a ISBN number |
4612 | +# or the project homepage. |
4613 | +#epub_identifier = '' |
4614 | + |
4615 | +# A unique identification for the text. |
4616 | +#epub_uid = '' |
4617 | + |
4618 | +# A tuple containing the cover image and cover page html template filenames. |
4619 | +#epub_cover = () |
4620 | + |
4621 | +# HTML files that should be inserted before the pages created by sphinx. |
4622 | +# The format is a list of tuples containing the path and title. |
4623 | +#epub_pre_files = [] |
4624 | + |
4625 | +# HTML files shat should be inserted after the pages created by sphinx. |
4626 | +# The format is a list of tuples containing the path and title. |
4627 | +#epub_post_files = [] |
4628 | + |
4629 | +# A list of files that should not be packed into the epub file. |
4630 | +#epub_exclude_files = [] |
4631 | + |
4632 | +# The depth of the table of contents in toc.ncx. |
4633 | +#epub_tocdepth = 3 |
4634 | + |
4635 | +# Allow duplicate toc entries. |
4636 | +#epub_tocdup = True |
4637 | |
4638 | === added file 'doc/index.rst' |
4639 | --- doc/index.rst 1970-01-01 00:00:00 +0000 |
4640 | +++ doc/index.rst 2012-05-30 18:23:19 +0000 |
4641 | @@ -0,0 +1,15 @@ |
4642 | +Akiban Persistit User Guide |
4643 | +=========================== |
4644 | +.. toctree:: |
4645 | + :maxdepth: 1 |
4646 | + |
4647 | + GettingStarted |
4648 | + BasicAPI |
4649 | + Transactions |
4650 | + PhysicalStorage |
4651 | + Configuration |
4652 | + Management |
4653 | + Security |
4654 | + Serialization |
4655 | + Miscellaneous |
4656 | + |
4657 | |
4658 | === removed file 'doc/overview-summary.txt' |
4659 | --- doc/overview-summary.txt 2011-04-26 02:10:48 +0000 |
4660 | +++ doc/overview-summary.txt 1970-01-01 00:00:00 +0000 |
4661 | @@ -1,107 +0,0 @@ |
4662 | - |
4663 | -Persistit 2.2 |
4664 | -============= |
4665 | - |
4666 | -Persistit(TM) is a small, lightweight Java(TM) library that provides simple, fast and reliable data persistence for Java applications. It is designed to be embedded in Java application programs and to operate free of administration by the end-user. |
4667 | - |
4668 | -This section provides a brief overview. See http://com.akiban.com/persistit/documentation/ for complete documentation. |
4669 | - |
4670 | -== API Overview |
4671 | - |
4672 | -Persistit stores data as key-value pairs in highly optimized B-Tree structures. Much like a Java Map implementation, Persistit associates at most one value with each unique instance of a key. |
4673 | - |
4674 | -Persistit provides interfaces to access and modify keys and their associated values. The developer writes code to construct key and value instances and to store, fetch, traverse and remove keys and records to and from the database. Persistit permits efficient multi-threaded concurrent access to database volumes. It is designed to minimize contention for critical resources and to maximize throughput on multi-processor machines. |
4675 | - |
4676 | -In addition to low-level access methods on keys and values, Persistit provides com.persistit.PersistitMap, which implements the java.util.SortedMap interface. PersistitMap uses the Persistit database as a backing store so that key/value pairs are persistent, potentially shared with all threads, and limited in number only by disk storage. (See PersistitMap.) |
4677 | - |
4678 | -Within Persistit, key values are _segmented_ and _ordered_. Segmented means that you can append multiple primitive values or Strings to construct a concatenated key. Ordered means that the methods that enumerate key values within a Persistit database do so in a specified natural order. (See Keys). |
4679 | - |
4680 | -A Persistit value may be any primitive value, any Serializable Java object, or an object of any class supported by a custom serialization helper class. When stored in the B-Tree, keys and values are represented by sequences of bytes. The byte sequence that represents a value may be of arbitrary length, bounded only by available heap memory. (See Values.) |
4681 | - |
4682 | -=== Access Methods |
4683 | - |
4684 | -The primary low-level interface for interacting with Persistit is +com.persistit.Exchange+. The Exchange class provides all methods for storing, deleting, fetching and traversing key/value pairs. These methods are summarized here and described in detail in the API documentation. |
4685 | - |
4686 | -Although the underlying Persistit database is designed for highly concurrent multi-threaded operation, the Exchange object itself is not thread-safe. Each thread should create and use its own Exchange object(s) when accessing the database. |
4687 | - |
4688 | -To create an Exchange you provide a Volume name (or alias) and a tree name in its constructor. The constructor will optionally create a new tree in that Volume if a tree having the specified name is not found. An application may construct an arbitrary number of Exchange objects. Creating a new Exchange has no effect on the database if the specified tree already exists. Tree creation is thread-safe: multiple threads concurrently constructing Exchanges using the same Tree name will safely result in the creation of only one new tree. |
4689 | - |
4690 | -An Exchange is a moderately complex object that requires several thousand bytes of heap space. Memory-constrained applications should construct Exchanges in moderate numbers. An Exchange internally maintains some optimization information such that references to nearby Keys within a tree are accelerated. Performance may benefit from using a different Exchange for each area of the Tree being accessed. |
4691 | - |
4692 | -Persistit offers Exchange pooling to avoid rapidly creating and destroying Exchange objects in multi-threaded applications. In particular, web applications may benefit from using the Exchange pool. |
4693 | - |
4694 | -An Exchange is always associated with a com.persistit.Key and a com.persistit.Value. Typically you work with an Exchange in one of the following patterns: |
4695 | -. Modify the Key, perform a +fetch+ operation, and extract the Value. |
4696 | -. Modify the Key, modify the Value, and then perform a +store+ operation. |
4697 | -. Modify the Key, and then perform a +remove+ operation. |
4698 | -. Optionally modify the Key, perform a +traverse+ operation, then read the resulting Key and/or Value. |
4699 | - |
4700 | -These four methods, plus a few other methods listed here, are the primary low-level interface to the database. Semantics are as follows: |
4701 | - |
4702 | -[horizontal] |
4703 | -+fetch+:: Reads the stored value associated with this Exchange's Key and modifies the Exchange’s Value to reflect that value. |
4704 | -+store+:: Inserts or replaces the key/value pair for the specified key in the Tree either by replacing the former value, if there was one, or inserting a new value. |
4705 | -+fetchAndStore+:: Fetches and then replaces the stored value. Upon completion, Value reflects the formerly stored value for the current Key. This operation is atomic, as opposed to sequential calls to fetch and store. |
4706 | -+remove+, +removeAll+, +removeKeyRange+:: Removes key/value pairs from the Tree. Versions of this method specify either a single key or a range of keys to be removed. |
4707 | -+fetchAndRemove+:: Fetches and then removes the stored value. Upon completion, Value reflects the formerly stored value for the current Key. This operation is atomic, as opposed to sequential calls to fetch and remove. |
4708 | -+traverse+, +next+, +previous+:: Modifies the Exchange’s Key and Value to reflect a successor or predecessor key within the tree. (See API documentation for com.persistit.Key for information on the order of traversal.) |
4709 | -+incrementValue+:: Atomically increments or decrements a long (64-bit integer) value associated with the current Key, and returns the modified value. If there is currently no value associated with the key then incrementValue creates one and assigns an initial value to it. This operation provides a convenient way for concurrent threads to safely allocate unique long integers without an explicit transaction scope. |
4710 | -+hasNext+, +hasPrevious+:: Indicates, without modifying the Exchange’s Value or Key objects, whether there is a successor or predecessor key in the Tree. |
4711 | -+getChangeCount+:: Number of times the Tree for this Exchange has changed. This count may be used as a reliable indicator of whether the Tree has changed since some earlier instant in time. For example, it is used to detect concurrent modifications by PersistitMap. |
4712 | - |
4713 | -Because Persistit permits concurrent operations by multiple threads, there is no guarantee that the underlying database will remain unchanged after any of these operations is completed. However, each of these methods operates atomically. That is, the inputs and outputs of each method are consistent with some valid state of the underlying Persistit backing store at some instant in time. The Value and Key objects for the Exchange represent that consistent state even if some other thread subsequently modifies the underlying database. |
4714 | - |
4715 | -=== PersistitMap |
4716 | - |
4717 | -Persistit provides an implementation of the java.util.SortedMap interface called com.persistit.PersistitMap. PersistitMap uses Persistit as its backing store, permitting large maps to be stored efficiently on disk using constant heap memory space. |
4718 | - |
4719 | -Keys for PersistitMap must conform to the constraints described above under Keys. Values must conform to the constraints described for Values. |
4720 | - |
4721 | -The constructor for PersistitMap takes an Exchange as its sole parameter. All key/value pairs of the Map are stored within the tree identified by this Exchange. The Key supplied by the Exchange becomes the root of a logical tree. For example: |
4722 | - |
4723 | -[source,java] |
4724 | ----- |
4725 | -Exchange ex = new Exchange("myVolume", "myTree", true); |
4726 | -ex.append("USA").append("MA"); |
4727 | -PersistitMap<String, String> map = new PersistitMap<String, String>(ex); |
4728 | -map.put("Boston", "Hub"); |
4729 | ----- |
4730 | - |
4731 | -places a key/value pair into the myTree with the concatenated key +{"USA ","MA","Boston"}+ and a value of +"Hub"+. |
4732 | - |
4733 | -Because Persistit is designed for concurrent operation it is possible (and often intended) for the backing store of PersistitMap to be changed by other threads while a java.util.Iterator is in use. Generally the expected behavior for an Iterator on a Map collection view is to throw a ConcurrentModificationException if the underlying collection changes. This is known as fail-fast behavior. PersistitMap implements this behavior by throwing a ConcurrentModificationException in the event the Tree containing the map changes. An application can detect that the map may have changed due to a programming error in case the design contract calls for it to remain unchanged by catching this exception. |
4734 | - |
4735 | -However, sometimes it may be desirable to use PersistitMap and its collections view interfaces to iterate across changing data. Internally, Persistit uses the traverse method to retrieve the next highest key in the key sort order in order to implement the Iterator’s hasNext and next methods. The result will depend on the content of the database at the instant these operations are performed. PersistitMap provides the method setAllowConcurrentModification to enable this behavior. By default, concurrent modifications are not allowed. |
4736 | -=== KeyFilter |
4737 | - |
4738 | -A +com.persistit.KeyFilter+ defines a subset of all possible key values. You can supply a KeyFilter to the traverse methods of an Exchange. You can also specify a KeyFilter for any Iterator returned by the collection views of a PersistitMap. In either case, the key/value pairs covered by traversing the database or iterating over the collection view are restricted to those selected by the KeyFilter. |
4739 | - |
4740 | -Use of a KeyFilter is illustrated by the following code fragment: |
4741 | - |
4742 | -[source,java] |
4743 | ----- |
4744 | -Exchange ex = new Exchange("myVolume", "myTree", true); |
4745 | -KeyFilter kf = new KeyFilter("{\"Bellini\":\"Busoni\"}"); |
4746 | -ex.append(Key.BEFORE); |
4747 | -while (ex.next(kf)) |
4748 | -{ |
4749 | - System.out.println(ex.getKey().reset().decodeString()); |
4750 | -} |
4751 | ----- |
4752 | - |
4753 | -This simple example emits the string-valued keys within myTree whose values fall alphabetically between “Bellini” and “Busoni”, inclusive. |
4754 | - |
4755 | - |
4756 | -== Transactions |
4757 | - |
4758 | -Persistit supports transactions with full isolation and optimistic concurrency control. An application may begin, commit or roll back the current transaction scope explicitly, executing multiple database operations in an atomic, consistent, isolated and (optionally) durable (ACID) manner. If the application does not explicitly define the scope of a transaction, each database operation implicitly runs within the scope of a separate transaction. Each Persistit transaction may optionally be committed to either memory or disk. Transactions committed to memory are much faster, but are not immediately durable. (See Transactions.) |
4759 | - |
4760 | -== Configuration |
4761 | - |
4762 | -To initialize Persistit the embedding application invokes one of the initialize methods of +com.persistit.Persistit+, passing either a +java.util.Properties+ object or the name of a properties file from which the Properties object derives its content. The following properties are defined for Persistit. Other properties may also reside in the Properties object or its backing file; Persistit simply ignores any property not listed here. |
4763 | - |
4764 | -== Logging API |
4765 | - |
4766 | -Persistit is writes various diagnostic and informational messages to a log. By default, the log is written as text to the file +persistit.log+ in the current working directory. However, a container application will usually have a logging architecture already in place, and Persistit provides a simple way to redirect its log output to the container application’s log. Adapters for Log4J and the Java Logging API are included; other logging systems are easy to adapt. |
4767 | - |
4768 | - |
Looks plausible.