16
16
17
17
package io .objectbox ;
18
18
19
+ import com .google .flatbuffers .FlatBufferBuilder ;
20
+ import io .objectbox .model .FlatStoreOptions ;
19
21
import org .greenrobot .essentials .io .IoUtils ;
20
22
21
23
import java .io .BufferedInputStream ;
37
39
import io .objectbox .annotation .apihint .Internal ;
38
40
import io .objectbox .exception .DbException ;
39
41
import io .objectbox .ideasonly .ModelUpdate ;
42
+ import io .objectbox .model .ValidateOnOpenMode ;
40
43
41
44
/**
42
45
* Builds a {@link BoxStore} with optional configurations. The class is not initiated directly; use
@@ -87,18 +90,32 @@ public class BoxStoreBuilder {
87
90
88
91
boolean debugRelations ;
89
92
93
+ long fileMode ;
94
+
90
95
int maxReaders ;
91
96
92
97
int queryAttempts ;
93
98
99
+ /** For DebugCursor. */
100
+ boolean skipReadSchema ;
101
+
102
+ boolean readOnly ;
103
+ boolean usePreviousCommit ;
104
+
105
+ short validateOnOpenMode ;
106
+ long validateOnOpenPageLimit ;
107
+
94
108
TxCallback <?> failedReadTxAttemptCallback ;
95
109
96
110
final List <EntityInfo <?>> entityInfoList = new ArrayList <>();
97
111
private Factory <InputStream > initialDbFileFactory ;
98
112
99
- /** Not for application use. */
113
+ /** Not for application use, for DebugCursor. */
114
+ @ Internal
100
115
public static BoxStoreBuilder createDebugWithoutModel () {
101
- return new BoxStoreBuilder ();
116
+ BoxStoreBuilder builder = new BoxStoreBuilder ();
117
+ builder .skipReadSchema = true ;
118
+ return builder ;
102
119
}
103
120
104
121
private BoxStoreBuilder () {
@@ -259,6 +276,17 @@ private static File getAndroidFilesDir(Object context) {
259
276
return filesDir ;
260
277
}
261
278
279
+ /**
280
+ * Specify
281
+ * <a href="https://en.wikipedia.org/wiki/File_system_permissions#Numeric_notation">unix-style file permissions</a>
282
+ * to use for the database directory and files.
283
+ * E.g. for {@code rw-rw-rw-} (owner, group, other) pass the octal code {@code 666}.
284
+ */
285
+ public BoxStoreBuilder fileMode (long mode ) {
286
+ this .fileMode = mode ;
287
+ return this ;
288
+ }
289
+
262
290
/**
263
291
* Sets the maximum number of concurrent readers. For most applications, the default is fine (> 100 readers).
264
292
* <p>
@@ -269,7 +297,6 @@ private static File getAndroidFilesDir(Object context) {
269
297
* For highly concurrent setups (e.g. you are using ObjectBox on the server side) it may make sense to increase the
270
298
* number.
271
299
*/
272
-
273
300
public BoxStoreBuilder maxReaders (int maxReaders ) {
274
301
this .maxReaders = maxReaders ;
275
302
return this ;
@@ -299,6 +326,63 @@ public BoxStoreBuilder maxSizeInKByte(long maxSizeInKByte) {
299
326
return this ;
300
327
}
301
328
329
+ /**
330
+ * Open the store in read-only mode: no schema update, no write transactions.
331
+ * <p>
332
+ * It is recommended to use this with {@link #usePreviousCommit()} to ensure no data is lost.
333
+ */
334
+ public BoxStoreBuilder readOnly () {
335
+ this .readOnly = true ;
336
+ return this ;
337
+ }
338
+
339
+ /**
340
+ * Ignores the latest data snapshot (committed transaction state) and uses the previous snapshot instead.
341
+ * When used with care (e.g. backup the DB files first), this option may also recover data removed by the latest
342
+ * transaction.
343
+ * <p>
344
+ * It is recommended to use this with {@link #readOnly()} to ensure no data is lost.
345
+ */
346
+ public BoxStoreBuilder usePreviousCommit () {
347
+ this .usePreviousCommit = true ;
348
+ return this ;
349
+ }
350
+
351
+ /**
352
+ * When a database is opened, ObjectBox can perform additional consistency checks on its database structure.
353
+ * Reliable file systems already guarantee consistency, so this is primarily meant to deal with unreliable
354
+ * OSes, file systems, or hardware.
355
+ * <p>
356
+ * Note: ObjectBox builds upon ACID storage, which already has strong consistency mechanisms in place.
357
+ *
358
+ * @param validateOnOpenMode One of {@link ValidateOnOpenMode}.
359
+ */
360
+ public BoxStoreBuilder validateOnOpen (short validateOnOpenMode ) {
361
+ if (validateOnOpenMode < ValidateOnOpenMode .None || validateOnOpenMode > ValidateOnOpenMode .Full ) {
362
+ throw new IllegalArgumentException ("Must be one of ValidateOnOpenMode" );
363
+ }
364
+ this .validateOnOpenMode = validateOnOpenMode ;
365
+ return this ;
366
+ }
367
+
368
+ /**
369
+ * To fine-tune {@link #validateOnOpen(short)}, you can specify a limit on how much data is looked at.
370
+ * This is measured in "pages" with a page typically holding 4000.
371
+ * Usually a low number (e.g. 1-20) is sufficient and does not impact startup performance significantly.
372
+ * <p>
373
+ * This can only be used with {@link ValidateOnOpenMode#Regular} and {@link ValidateOnOpenMode#WithLeaves}.
374
+ */
375
+ public BoxStoreBuilder validateOnOpenPageLimit (long limit ) {
376
+ if (validateOnOpenMode != ValidateOnOpenMode .Regular && validateOnOpenMode != ValidateOnOpenMode .WithLeaves ) {
377
+ throw new IllegalStateException ("Must call validateOnOpen(mode) with mode Regular or WithLeaves first" );
378
+ }
379
+ if (limit < 1 ) {
380
+ throw new IllegalArgumentException ("limit must be positive" );
381
+ }
382
+ this .validateOnOpenPageLimit = limit ;
383
+ return this ;
384
+ }
385
+
302
386
/**
303
387
* @deprecated Use {@link #debugFlags} instead.
304
388
*/
@@ -370,6 +454,39 @@ public BoxStoreBuilder initialDbFile(Factory<InputStream> initialDbFileFactory)
370
454
return this ;
371
455
}
372
456
457
+ byte [] buildFlatStoreOptions (String canonicalPath ) {
458
+ FlatBufferBuilder fbb = new FlatBufferBuilder ();
459
+ // FlatBuffer default values are set in generated code, e.g. may be different from here, so always store value.
460
+ fbb .forceDefaults (true );
461
+
462
+ // Add non-integer values first...
463
+ int directoryPathOffset = fbb .createString (canonicalPath );
464
+
465
+ FlatStoreOptions .startFlatStoreOptions (fbb );
466
+
467
+ // ...then build options.
468
+ FlatStoreOptions .addDirectoryPath (fbb , directoryPathOffset );
469
+ FlatStoreOptions .addMaxDbSizeInKByte (fbb , maxSizeInKByte );
470
+ FlatStoreOptions .addFileMode (fbb , fileMode );
471
+ FlatStoreOptions .addMaxReaders (fbb , maxReaders );
472
+ if (validateOnOpenMode != 0 ) {
473
+ FlatStoreOptions .addValidateOnOpen (fbb , validateOnOpenMode );
474
+ if (validateOnOpenPageLimit != 0 ) {
475
+ FlatStoreOptions .addValidateOnOpenPageLimit (fbb , validateOnOpenPageLimit );
476
+ }
477
+ }
478
+ if (skipReadSchema ) FlatStoreOptions .addSkipReadSchema (fbb , skipReadSchema );
479
+ if (usePreviousCommit ) FlatStoreOptions .addUsePreviousCommit (fbb , usePreviousCommit );
480
+ if (readOnly ) FlatStoreOptions .addReadOnly (fbb , readOnly );
481
+ if (debugFlags != 0 ) {
482
+ FlatStoreOptions .addDebugFlags (fbb , debugFlags );
483
+ }
484
+
485
+ int offset = FlatStoreOptions .endFlatStoreOptions (fbb );
486
+ fbb .finish (offset );
487
+ return fbb .sizedByteArray ();
488
+ }
489
+
373
490
/**
374
491
* Builds a {@link BoxStore} using any given configuration.
375
492
*/
0 commit comments