1 | /*
|
---|
2 | * Copyright (c) 2012 Jan Kotek
|
---|
3 | *
|
---|
4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
---|
5 | * you may not use this file except in compliance with the License.
|
---|
6 | * You may obtain a copy of the License at
|
---|
7 | *
|
---|
8 | * http://www.apache.org/licenses/LICENSE-2.0
|
---|
9 | *
|
---|
10 | * Unless required by applicable law or agreed to in writing, software
|
---|
11 | * distributed under the License is distributed on an "AS IS" BASIS,
|
---|
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
---|
13 | * See the License for the specific language governing permissions and
|
---|
14 | * limitations under the License.
|
---|
15 | */
|
---|
16 |
|
---|
17 | package org.mapdb;
|
---|
18 |
|
---|
19 | import org.mapdb.EngineWrapper.ByteTransformEngine;
|
---|
20 | import org.mapdb.EngineWrapper.ReadOnlyEngine;
|
---|
21 |
|
---|
22 | import java.io.File;
|
---|
23 | import java.io.IOError;
|
---|
24 | import java.io.IOException;
|
---|
25 | import java.io.UnsupportedEncodingException;
|
---|
26 | import java.util.NavigableSet;
|
---|
27 | import java.util.Set;
|
---|
28 |
|
---|
29 | /**
|
---|
30 | * A builder class for creating and opening a database.
|
---|
31 | *
|
---|
32 | * @author Jan Kotek
|
---|
33 | */
|
---|
34 | public class DBMaker {
|
---|
35 |
|
---|
36 | protected static final byte CACHE_DISABLE = 0;
|
---|
37 | protected static final byte CACHE_FIXED_HASH_TABLE = 1;
|
---|
38 | protected static final byte CACHE_HARD_REF = 2;
|
---|
39 | protected static final byte CACHE_WEAK_REF = 3;
|
---|
40 | protected static final byte CACHE_SOFT_REF = 4;
|
---|
41 | protected static final byte CACHE_LRU = 5;
|
---|
42 |
|
---|
43 | protected byte _cache = CACHE_FIXED_HASH_TABLE;
|
---|
44 | protected int _cacheSize = 1024*32;
|
---|
45 |
|
---|
46 | /** file to open, if null opens in memory store */
|
---|
47 | protected File _file;
|
---|
48 |
|
---|
49 | protected boolean _journalEnabled = true;
|
---|
50 |
|
---|
51 | protected boolean _asyncWriteEnabled = true;
|
---|
52 | protected int _asyncFlushDelay = 100;
|
---|
53 |
|
---|
54 | protected boolean _deleteFilesAfterClose = false;
|
---|
55 | protected boolean _readOnly = false;
|
---|
56 | protected boolean _closeOnJvmShutdown = false;
|
---|
57 |
|
---|
58 | protected boolean _compressionEnabled = false;
|
---|
59 |
|
---|
60 | protected byte[] _xteaEncryptionKey = null;
|
---|
61 |
|
---|
62 | protected int _freeSpaceReclaimQ = 5;
|
---|
63 |
|
---|
64 | protected boolean _checksumEnabled = false;
|
---|
65 |
|
---|
66 | protected boolean _ifInMemoryUseDirectBuffer = false;
|
---|
67 |
|
---|
68 | protected boolean _failOnWrongHeader = false;
|
---|
69 |
|
---|
70 | protected boolean _RAF = false;
|
---|
71 | protected boolean _powerSavingMode = false;
|
---|
72 | protected boolean _appendStorage;
|
---|
73 |
|
---|
74 | /** use static factory methods, or make subclass */
|
---|
75 | protected DBMaker(){}
|
---|
76 |
|
---|
77 | /** Creates new in-memory database. Changes are lost after JVM exits.
|
---|
78 | * <p/>
|
---|
79 | * This will use HEAP memory so Garbage Collector is affected.
|
---|
80 | */
|
---|
81 | public static DBMaker newMemoryDB(){
|
---|
82 | DBMaker m = new DBMaker();
|
---|
83 | m._file = null;
|
---|
84 | return m;
|
---|
85 | }
|
---|
86 |
|
---|
87 | /** Creates new in-memory database. Changes are lost after JVM exits.
|
---|
88 | * <p/>
|
---|
89 | * This will use DirectByteBuffer outside of HEAP, so Garbage Collector is not affected
|
---|
90 | *
|
---|
91 | */
|
---|
92 | public static DBMaker newDirectMemoryDB(){
|
---|
93 | DBMaker m = new DBMaker();
|
---|
94 | m._file = null;
|
---|
95 | m._ifInMemoryUseDirectBuffer = true;
|
---|
96 | return m;
|
---|
97 | }
|
---|
98 |
|
---|
99 |
|
---|
100 | /**
|
---|
101 | * Creates or open append-only database stored in file.
|
---|
102 | * This database uses format otherthan usual file db
|
---|
103 | *
|
---|
104 | * @param file
|
---|
105 | * @return maker
|
---|
106 | */
|
---|
107 | public static DBMaker newAppendFileDB(File file) {
|
---|
108 | DBMaker m = new DBMaker();
|
---|
109 | m._file = file;
|
---|
110 | m._appendStorage = true;
|
---|
111 | return m;
|
---|
112 | }
|
---|
113 |
|
---|
114 |
|
---|
115 |
|
---|
116 | /**
|
---|
117 | * Create new BTreeMap backed by temporary file storage.
|
---|
118 | * This is quick way to create 'throw away' collection.
|
---|
119 | *
|
---|
120 | * <p>Storage is created in temp folder and deleted on JVM shutdown
|
---|
121 | */
|
---|
122 | public static <K,V> BTreeMap<K,V> newTempTreeMap(){
|
---|
123 | return newTempFileDB()
|
---|
124 | .deleteFilesAfterClose()
|
---|
125 | .closeOnJvmShutdown()
|
---|
126 | .writeAheadLogDisable()
|
---|
127 | .make()
|
---|
128 | .getTreeMap("temp");
|
---|
129 | }
|
---|
130 |
|
---|
131 | /**
|
---|
132 | * Create new HTreeMap backed by temporary file storage.
|
---|
133 | * This is quick way to create 'throw away' collection.
|
---|
134 | *
|
---|
135 | * <p>Storage is created in temp folder and deleted on JVM shutdown
|
---|
136 | */
|
---|
137 | public static <K,V> HTreeMap<K,V> newTempHashMap(){
|
---|
138 | return newTempFileDB()
|
---|
139 | .deleteFilesAfterClose()
|
---|
140 | .closeOnJvmShutdown()
|
---|
141 | .writeAheadLogDisable()
|
---|
142 | .make()
|
---|
143 | .getHashMap("temp");
|
---|
144 | }
|
---|
145 |
|
---|
146 | /**
|
---|
147 | * Create new TreeSet backed by temporary file storage.
|
---|
148 | * This is quick way to create 'throw away' collection.
|
---|
149 | *
|
---|
150 | * <p>Storage is created in temp folder and deleted on JVM shutdown
|
---|
151 | */
|
---|
152 | public static <K> NavigableSet<K> newTempTreeSet(){
|
---|
153 | return newTempFileDB()
|
---|
154 | .deleteFilesAfterClose()
|
---|
155 | .closeOnJvmShutdown()
|
---|
156 | .writeAheadLogDisable()
|
---|
157 | .make()
|
---|
158 | .getTreeSet("temp");
|
---|
159 | }
|
---|
160 |
|
---|
161 | /**
|
---|
162 | * Create new HashSet backed by temporary file storage.
|
---|
163 | * This is quick way to create 'throw away' collection.
|
---|
164 | * <p>
|
---|
165 | * Storage is created in temp folder and deleted on JVM shutdown
|
---|
166 | */
|
---|
167 | public static <K> Set<K> newTempHashSet(){
|
---|
168 | return newTempFileDB()
|
---|
169 | .deleteFilesAfterClose()
|
---|
170 | .closeOnJvmShutdown()
|
---|
171 | .writeAheadLogDisable()
|
---|
172 | .make()
|
---|
173 | .getHashSet("temp");
|
---|
174 | }
|
---|
175 |
|
---|
176 | /**
|
---|
177 | * Creates new database in temporary folder.
|
---|
178 | *
|
---|
179 | * @return
|
---|
180 | */
|
---|
181 | public static DBMaker newTempFileDB() {
|
---|
182 | try {
|
---|
183 | return newFileDB(File.createTempFile("mapdb-temp","db"));
|
---|
184 | } catch (IOException e) {
|
---|
185 | throw new IOError(e);
|
---|
186 | }
|
---|
187 | }
|
---|
188 |
|
---|
189 |
|
---|
190 | /** Creates or open database stored in file. */
|
---|
191 | public static DBMaker newFileDB(File file){
|
---|
192 | DBMaker m = new DBMaker();
|
---|
193 | m._file = file;
|
---|
194 | return m;
|
---|
195 | }
|
---|
196 |
|
---|
197 |
|
---|
198 |
|
---|
199 | /**
|
---|
200 | * Transaction journal is enabled by default
|
---|
201 | * You must call <b>DB.commit()</b> to save your changes.
|
---|
202 | * It is possible to disable transaction journal for better write performance
|
---|
203 | * In this case all integrity checks are sacrificed for faster speed.
|
---|
204 | * <p/>
|
---|
205 | * If transaction journal is disabled, all changes are written DIRECTLY into store.
|
---|
206 | * You must call DB.close() method before exit,
|
---|
207 | * otherwise your store <b>WILL BE CORRUPTED</b>
|
---|
208 | *
|
---|
209 | *
|
---|
210 | * @return this builder
|
---|
211 | */
|
---|
212 | public DBMaker writeAheadLogDisable(){
|
---|
213 | this._journalEnabled = false;
|
---|
214 | return this;
|
---|
215 | }
|
---|
216 |
|
---|
217 | /**
|
---|
218 | * Instance cache is enabled by default.
|
---|
219 | * This greatly decreases serialization overhead and improves performance.
|
---|
220 | * Call this method to disable instance cache, so an object will always be deserialized.
|
---|
221 | * <p/>
|
---|
222 | * This may workaround some problems
|
---|
223 | *
|
---|
224 | * @return this builder
|
---|
225 | */
|
---|
226 | public DBMaker cacheDisable(){
|
---|
227 | this._cache = CACHE_DISABLE;
|
---|
228 | return this;
|
---|
229 | }
|
---|
230 |
|
---|
231 | /**
|
---|
232 | * Enables unbounded hard reference cache.
|
---|
233 | * This cache is good if you have lot of available memory.
|
---|
234 | * <p/>
|
---|
235 | * All fetched records are added to HashMap and stored with hard reference.
|
---|
236 | * To prevent OutOfMemoryExceptions JDBM monitors free memory,
|
---|
237 | * if it is bellow 25% cache is cleared.
|
---|
238 | *
|
---|
239 | * @return this builder
|
---|
240 | */
|
---|
241 | public DBMaker cacheHardRefEnable(){
|
---|
242 | this._cache = CACHE_HARD_REF;
|
---|
243 | return this;
|
---|
244 | }
|
---|
245 |
|
---|
246 |
|
---|
247 | /**
|
---|
248 | * Enables unbounded cache which uses <code>WeakReference</code>.
|
---|
249 | * Items are removed from cache by Garbage Collector
|
---|
250 | *
|
---|
251 | * @return this builder
|
---|
252 | */
|
---|
253 | public DBMaker cacheWeakRefEnable(){
|
---|
254 | this._cache = CACHE_WEAK_REF;
|
---|
255 | return this;
|
---|
256 | }
|
---|
257 |
|
---|
258 | /**
|
---|
259 | * Enables unbounded cache which uses <code>SoftReference</code>.
|
---|
260 | * Items are removed from cache by Garbage Collector
|
---|
261 | *
|
---|
262 | * @return this builder
|
---|
263 | */
|
---|
264 | public DBMaker cacheSoftRefEnable(){
|
---|
265 | this._cache = CACHE_SOFT_REF;
|
---|
266 | return this;
|
---|
267 | }
|
---|
268 |
|
---|
269 | /**
|
---|
270 | * Enables Least Recently Used cache. It is fixed size cache and it removes less used items to make space.
|
---|
271 | *
|
---|
272 | * @return this builder
|
---|
273 | */
|
---|
274 | public DBMaker cacheLRUEnable(){
|
---|
275 | this._cache = CACHE_LRU;
|
---|
276 | return this;
|
---|
277 | }
|
---|
278 | /**
|
---|
279 | * Enables compatibility storage mode for 32bit JVMs.
|
---|
280 | * <p/>
|
---|
281 | * By default MapDB uses memory mapped files. However 32bit JVM can only address 2GB of memory.
|
---|
282 | * Also some older JVMs do not handle large memory mapped files well.
|
---|
283 | * We can use {@code RandomAccessFile} which it is slower, but safer and more compatible.
|
---|
284 | * Use this if you are experiencing <b>java.lang.OutOfMemoryError: Map failed</b> exceptions
|
---|
285 | */
|
---|
286 | public DBMaker randomAccessFileEnable() {
|
---|
287 | this._RAF = true;
|
---|
288 | return this;
|
---|
289 | }
|
---|
290 |
|
---|
291 |
|
---|
292 | /**
|
---|
293 | * Check current JVM for known problems. If JVM does not handle large memory files well, this option
|
---|
294 | * disables memory mapped files, and use safer and slower {@code RandomAccessFile} instead.
|
---|
295 | */
|
---|
296 | public DBMaker randomAccessFileEnableIfNeeded() {
|
---|
297 | this._RAF = !Utils.JVMSupportsLargeMappedFiles();
|
---|
298 | return this;
|
---|
299 | }
|
---|
300 |
|
---|
301 | /**
|
---|
302 | * Set cache size. Interpretations depends on cache type.
|
---|
303 | * For fixed size caches (such as FixedHashTable cache) it is maximal number of items in cache.
|
---|
304 | * <p/>
|
---|
305 | * For unbounded caches (such as HardRef cache) it is initial capacity of underlying table (HashMap).
|
---|
306 | * <p/>
|
---|
307 | * Default cache size is 32768.
|
---|
308 | *
|
---|
309 | * @param cacheSize new cache size
|
---|
310 | * @return this builder
|
---|
311 | */
|
---|
312 | public DBMaker cacheSize(int cacheSize){
|
---|
313 | this._cacheSize = cacheSize;
|
---|
314 | return this;
|
---|
315 | }
|
---|
316 |
|
---|
317 |
|
---|
318 | /**
|
---|
319 | * By default all modifications are queued and written into disk on Background Writer Thread.
|
---|
320 | * So all modifications are performed in asynchronous mode and do not block.
|
---|
321 | * <p/>
|
---|
322 | * It is possible to disable Background Writer Thread, but this greatly hurts concurrency.
|
---|
323 | * Without async writes, all threads blocks until all previous writes are not finished (single big lock).
|
---|
324 | *
|
---|
325 | * <p/>
|
---|
326 | * This may workaround some problems
|
---|
327 | *
|
---|
328 | * @return this builder
|
---|
329 | */
|
---|
330 | public DBMaker asyncWriteDisable(){
|
---|
331 | this._asyncWriteEnabled = false;
|
---|
332 | return this;
|
---|
333 | }
|
---|
334 |
|
---|
335 | /**
|
---|
336 | * //TODO put this nice comment somewhere
|
---|
337 | * By default all objects are serialized in Background Writer Thread.
|
---|
338 | * <p/>
|
---|
339 | * This may improve performance. For example with single thread access, Async Serialization offloads
|
---|
340 | * lot of work to second core. Or when multiple values are added into single tree node,
|
---|
341 | * node has to be serialized only once. Without Async Serialization node is serialized each time
|
---|
342 | * node is updated.
|
---|
343 | * <p/>
|
---|
344 | * On other side Async Serialization moves all serialization into single thread. This
|
---|
345 | * hurts performance with many concurrent-independent updates.
|
---|
346 | * <p/>
|
---|
347 | * Async Serialization may also produce some unexpected results when your data classes are not
|
---|
348 | * immutable. Consider example bellow. If Async Serialization is disabled, it always prints 'Peter'.
|
---|
349 | * If it is enabled (by default) it creates race condition and randomly prints 'Peter' or 'Jack',
|
---|
350 | * <pre>
|
---|
351 | * Person person = new Person();
|
---|
352 | * person.setName("Peter");
|
---|
353 | * map.put(id, person)
|
---|
354 | * person.setName("Jack");
|
---|
355 | * //long pause
|
---|
356 | * println(map.get(id).getName());
|
---|
357 | * </pre>
|
---|
358 | *
|
---|
359 | * <p/>
|
---|
360 | * This may also workaround some problems
|
---|
361 | *
|
---|
362 | * @return this builder
|
---|
363 | */
|
---|
364 |
|
---|
365 |
|
---|
366 | /**
|
---|
367 | * Set flush iterval for write cache, by default is 0
|
---|
368 | * <p/>
|
---|
369 | * When BTreeMap is constructed from ordered set, tree node size is increasing linearly with each
|
---|
370 | * item added. Each time new key is added to tree node, its size changes and
|
---|
371 | * storage needs to find new place. So constructing BTreeMap from ordered set leads to large
|
---|
372 | * store fragmentation.
|
---|
373 | * <p/>
|
---|
374 | * Setting flush interval is workaround as BTreeMap node is always updated in memory (write cache)
|
---|
375 | * and only final version of node is stored on disk.
|
---|
376 | *
|
---|
377 | *
|
---|
378 | * @param delay flush write cache every N miliseconds
|
---|
379 | * @return this builder
|
---|
380 | */
|
---|
381 | public DBMaker asyncFlushDelay(int delay){
|
---|
382 | _asyncFlushDelay = delay;
|
---|
383 | return this;
|
---|
384 | }
|
---|
385 |
|
---|
386 |
|
---|
387 | /**
|
---|
388 | * Try to delete files after DB is closed.
|
---|
389 | * File deletion may silently fail, especially on Windows where buffer needs to be unmapped file delete.
|
---|
390 | *
|
---|
391 | * @return this builder
|
---|
392 | */
|
---|
393 | public DBMaker deleteFilesAfterClose(){
|
---|
394 | this._deleteFilesAfterClose = true;
|
---|
395 | return this;
|
---|
396 | }
|
---|
397 |
|
---|
398 | /**
|
---|
399 | * Adds JVM shutdown hook and closes DB just before JVM;
|
---|
400 | *
|
---|
401 | * @return this builder
|
---|
402 | */
|
---|
403 | public DBMaker closeOnJvmShutdown(){
|
---|
404 | this._closeOnJvmShutdown = true;
|
---|
405 | return this;
|
---|
406 | }
|
---|
407 |
|
---|
408 | /**
|
---|
409 | * Enables record compression.
|
---|
410 | * <p/>
|
---|
411 | * Make sure you enable this every time you reopen store, otherwise record de-serialization fails unpredictably.
|
---|
412 | *
|
---|
413 | * @return this builder
|
---|
414 | */
|
---|
415 | public DBMaker compressionEnable(){
|
---|
416 | this._compressionEnabled = true;
|
---|
417 | return this;
|
---|
418 | }
|
---|
419 |
|
---|
420 |
|
---|
421 | /**
|
---|
422 | * Encrypt storage using XTEA algorithm.
|
---|
423 | * <p/>
|
---|
424 | * XTEA is sound encryption algorithm. However implementation in JDBM was not peer-reviewed.
|
---|
425 | * JDBM only encrypts records data, so attacker may see number of records and their sizes.
|
---|
426 | * <p/>
|
---|
427 | * Make sure you enable this every time you reopen store, otherwise record de-serialization fails unpredictably.
|
---|
428 | *
|
---|
429 | * @param password for encryption
|
---|
430 | * @return this builder
|
---|
431 | */
|
---|
432 | public DBMaker encryptionEnable(String password){
|
---|
433 | try {
|
---|
434 | return encryptionEnable(password.getBytes(Utils.UTF8));
|
---|
435 | } catch (UnsupportedEncodingException e) {
|
---|
436 | throw new RuntimeException(e);
|
---|
437 | }
|
---|
438 | }
|
---|
439 |
|
---|
440 |
|
---|
441 |
|
---|
442 | /**
|
---|
443 | * Encrypt storage using XTEA algorithm.
|
---|
444 | * <p/>
|
---|
445 | * XTEA is sound encryption algorithm. However implementation in JDBM was not peer-reviewed.
|
---|
446 | * JDBM only encrypts records data, so attacker may see number of records and their sizes.
|
---|
447 | * <p/>
|
---|
448 | * Make sure you enable this every time you reopen store, otherwise record de-serialization fails unpredictably.
|
---|
449 | *
|
---|
450 | * @param password for encryption
|
---|
451 | * @return this builder
|
---|
452 | */
|
---|
453 | public DBMaker encryptionEnable(byte[] password){
|
---|
454 | _xteaEncryptionKey = password;
|
---|
455 | return this;
|
---|
456 | }
|
---|
457 |
|
---|
458 |
|
---|
459 | /**
|
---|
460 | * Adds CRC32 checksum at end of each record to check data integrity.
|
---|
461 | * It throws 'IOException("CRC32 does not match, data broken")' on de-serialization if data are corrupted
|
---|
462 | * <p/>
|
---|
463 | * Make sure you enable this every time you reopen store, otherwise record de-serialization fails.
|
---|
464 | *
|
---|
465 | * @return this builder
|
---|
466 | */
|
---|
467 | public DBMaker checksumEnable(){
|
---|
468 | this._checksumEnabled = true;
|
---|
469 | return this;
|
---|
470 | }
|
---|
471 |
|
---|
472 |
|
---|
473 | /**
|
---|
474 | * Open store in read-only mode. Any modification attempt will throw
|
---|
475 | * <code>UnsupportedOperationException("Read-only")</code>
|
---|
476 | *
|
---|
477 | * @return this builder
|
---|
478 | */
|
---|
479 | public DBMaker readOnly(){
|
---|
480 | this._readOnly = true;
|
---|
481 | return this;
|
---|
482 | }
|
---|
483 |
|
---|
484 |
|
---|
485 |
|
---|
486 | /**
|
---|
487 | * Set free space reclaim Q. It is value from 0 to 10, indicating how eagerly MapDB
|
---|
488 | * searchs for free space inside store to reuse, before expanding store file.
|
---|
489 | * 0 means that no free space will be reused and store file will just grow (effectively append only).
|
---|
490 | * 10 means that MapDB tries really hard to reuse free space, even if it may hurt performance.
|
---|
491 | * Default value is 5;
|
---|
492 | *
|
---|
493 | *
|
---|
494 | * @return this builder
|
---|
495 | */
|
---|
496 | public DBMaker freeSpaceReclaimQ(int q){
|
---|
497 | if(q<0||q>10) throw new IllegalArgumentException("wrong Q");
|
---|
498 | this._freeSpaceReclaimQ = q;
|
---|
499 | return this;
|
---|
500 | }
|
---|
501 |
|
---|
502 | /**
|
---|
503 | * Enables power saving mode.
|
---|
504 | * Typically MapDB runs daemon threads in infinitive cycle with delays and spin locks:
|
---|
505 | * <pre>
|
---|
506 | * while(true){
|
---|
507 | * Thread.sleep(1000);
|
---|
508 | * doSomething();
|
---|
509 | * }
|
---|
510 | *
|
---|
511 | * while(write_finished){
|
---|
512 | * write_chunk;
|
---|
513 | * sleep(10 nanoseconds) //so OS gets chance to finish async writing
|
---|
514 | * }
|
---|
515 | *
|
---|
516 | * </pre>
|
---|
517 | * This brings bit more stability (prevents deadlocks) and some extra speed.
|
---|
518 | * However it causes higher CPU usage then necessary, also CPU wakes-up every
|
---|
519 | * N seconds.
|
---|
520 | * <p>
|
---|
521 | * On power constrained devices (phones, laptops..) trading speed for energy
|
---|
522 | * consumption is not desired. So this settings tells MapDB to prefer
|
---|
523 | * energy efficiency over speed and stability. This is global settings, so
|
---|
524 | * this settings may affects any MapDB part where this settings makes sense
|
---|
525 | * <p>
|
---|
526 | * Currently is used only in {@link AsyncWriteEngine} where power settings
|
---|
527 | * may prevent Background Writer Thread from exiting, if main thread dies.
|
---|
528 | *
|
---|
529 | * @return this builder
|
---|
530 | */
|
---|
531 | // public DBMaker powerSavingModeEnable(){
|
---|
532 | // this._powerSavingMode = true;
|
---|
533 | // return this;
|
---|
534 | // }
|
---|
535 |
|
---|
536 |
|
---|
537 | /** constructs DB using current settings */
|
---|
538 | public DB make(){
|
---|
539 | return new DB(makeEngine());
|
---|
540 | }
|
---|
541 |
|
---|
542 |
|
---|
543 | public TxMaker makeTxMaker(){
|
---|
544 | return new TxMaker(makeEngine());
|
---|
545 | }
|
---|
546 |
|
---|
547 | /** constructs Engine using current settings */
|
---|
548 | public Engine makeEngine(){
|
---|
549 |
|
---|
550 |
|
---|
551 | if(_readOnly && _file==null)
|
---|
552 | throw new UnsupportedOperationException("Can not open in-memory DB in read-only mode.");
|
---|
553 |
|
---|
554 | if(_readOnly && !_file.exists() && !_appendStorage){
|
---|
555 | throw new UnsupportedOperationException("Can not open non-existing file in read-only mode.");
|
---|
556 | }
|
---|
557 |
|
---|
558 | Engine engine;
|
---|
559 |
|
---|
560 | if(!_appendStorage){
|
---|
561 | Volume.Factory folFac = _file == null?
|
---|
562 | Volume.memoryFactory(_ifInMemoryUseDirectBuffer):
|
---|
563 | Volume.fileFactory(_readOnly, _RAF, _file);
|
---|
564 |
|
---|
565 | engine = _journalEnabled ?
|
---|
566 | //TODO add extra params
|
---|
567 | //new StoreWAL(folFac, _freeSpaceReclaimDisabled, _deleteFilesAfterClose, _failOnWrongHeader, _readOnly):
|
---|
568 | //new StoreDirect(folFac, _freeSpaceReclaimDisabled, _deleteFilesAfterClose , _failOnWrongHeader, _readOnly);
|
---|
569 | new StoreWAL(folFac, _readOnly,_deleteFilesAfterClose):
|
---|
570 | new StoreDirect(folFac, _readOnly,_deleteFilesAfterClose);
|
---|
571 | }else{
|
---|
572 | if(_file==null) throw new UnsupportedOperationException("Append Storage format is not supported with in-memory dbs");
|
---|
573 | engine = new StoreAppend(_file, _RAF, _readOnly, !_journalEnabled);
|
---|
574 | }
|
---|
575 |
|
---|
576 | if(_checksumEnabled){
|
---|
577 | engine = new ByteTransformEngine(engine, Serializer.CRC32_CHECKSUM);
|
---|
578 | }
|
---|
579 |
|
---|
580 | if(_xteaEncryptionKey!=null){
|
---|
581 | engine = new ByteTransformEngine(engine, new EncryptionXTEA(_xteaEncryptionKey));
|
---|
582 | }
|
---|
583 |
|
---|
584 |
|
---|
585 | if(_compressionEnabled){
|
---|
586 | engine = new ByteTransformEngine(engine, CompressLZF.SERIALIZER);
|
---|
587 | }
|
---|
588 |
|
---|
589 |
|
---|
590 | AsyncWriteEngine engineAsync = null;
|
---|
591 | if(_asyncWriteEnabled && !_readOnly){
|
---|
592 | engineAsync = new AsyncWriteEngine(engine,!_journalEnabled, _powerSavingMode, _asyncFlushDelay);
|
---|
593 | engine = engineAsync;
|
---|
594 | }
|
---|
595 |
|
---|
596 |
|
---|
597 | engine = new SnapshotEngine(engine);
|
---|
598 |
|
---|
599 | if(_cache == CACHE_DISABLE){
|
---|
600 | //do not wrap engine in cache
|
---|
601 | }if(_cache == CACHE_FIXED_HASH_TABLE){
|
---|
602 | engine = new CacheHashTable(engine,_cacheSize);
|
---|
603 | }else if (_cache == CACHE_HARD_REF){
|
---|
604 | engine = new CacheHardRef(engine,_cacheSize);
|
---|
605 | }else if (_cache == CACHE_WEAK_REF){
|
---|
606 | engine = new CacheWeakSoftRef(engine,true);
|
---|
607 | }else if (_cache == CACHE_SOFT_REF){
|
---|
608 | engine = new CacheWeakSoftRef(engine,false);
|
---|
609 | }else if (_cache == CACHE_LRU){
|
---|
610 | engine = new CacheLRU(engine, _cacheSize);
|
---|
611 | }
|
---|
612 |
|
---|
613 |
|
---|
614 | if(_readOnly)
|
---|
615 | engine = new ReadOnlyEngine(engine);
|
---|
616 |
|
---|
617 | if(engineAsync!=null)
|
---|
618 | engineAsync.setParentEngineReference(engine);
|
---|
619 |
|
---|
620 | if(_closeOnJvmShutdown){
|
---|
621 | final Engine engine2 = engine;
|
---|
622 | Runtime.getRuntime().addShutdownHook(new Thread("JDBM shutdown") {
|
---|
623 | @Override
|
---|
624 | public void run() {
|
---|
625 |
|
---|
626 | // for JOSM plugin ImageryCache
|
---|
627 | org.openstreetmap.josm.plugins.imagerycache.TileDAOMapDB.dbNotAvailable = true;
|
---|
628 | if(!engine2.isClosed())
|
---|
629 | engine2.close();
|
---|
630 | }
|
---|
631 | });
|
---|
632 | }
|
---|
633 |
|
---|
634 | return engine;
|
---|
635 | }
|
---|
636 |
|
---|
637 |
|
---|
638 |
|
---|
639 |
|
---|
640 | }
|
---|