1616
1717package io .objectbox ;
1818
19+ import com .google .flatbuffers .FlatBufferBuilder ;
20+ import io .objectbox .model .FlatStoreOptions ;
1921import org .greenrobot .essentials .io .IoUtils ;
2022
2123import java .io .BufferedInputStream ;
3739import io .objectbox .annotation .apihint .Internal ;
3840import io .objectbox .exception .DbException ;
3941import io .objectbox .ideasonly .ModelUpdate ;
42+ import io .objectbox .model .ValidateOnOpenMode ;
4043
4144/**
4245 * Builds a {@link BoxStore} with optional configurations. The class is not initiated directly; use
@@ -87,18 +90,32 @@ public class BoxStoreBuilder {
8790
8891 boolean debugRelations ;
8992
93+ long fileMode ;
94+
9095 int maxReaders ;
9196
9297 int queryAttempts ;
9398
99+ /** For DebugCursor. */
100+ boolean skipReadSchema ;
101+
102+ boolean readOnly ;
103+ boolean usePreviousCommit ;
104+
105+ short validateOnOpenMode ;
106+ long validateOnOpenPageLimit ;
107+
94108 TxCallback <?> failedReadTxAttemptCallback ;
95109
96110 final List <EntityInfo <?>> entityInfoList = new ArrayList <>();
97111 private Factory <InputStream > initialDbFileFactory ;
98112
99- /** Not for application use. */
113+ /** Not for application use, for DebugCursor. */
114+ @ Internal
100115 public static BoxStoreBuilder createDebugWithoutModel () {
101- return new BoxStoreBuilder ();
116+ BoxStoreBuilder builder = new BoxStoreBuilder ();
117+ builder .skipReadSchema = true ;
118+ return builder ;
102119 }
103120
104121 private BoxStoreBuilder () {
@@ -259,6 +276,17 @@ private static File getAndroidFilesDir(Object context) {
259276 return filesDir ;
260277 }
261278
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+
262290 /**
263291 * Sets the maximum number of concurrent readers. For most applications, the default is fine (> 100 readers).
264292 * <p>
@@ -269,7 +297,6 @@ private static File getAndroidFilesDir(Object context) {
269297 * For highly concurrent setups (e.g. you are using ObjectBox on the server side) it may make sense to increase the
270298 * number.
271299 */
272-
273300 public BoxStoreBuilder maxReaders (int maxReaders ) {
274301 this .maxReaders = maxReaders ;
275302 return this ;
@@ -299,6 +326,63 @@ public BoxStoreBuilder maxSizeInKByte(long maxSizeInKByte) {
299326 return this ;
300327 }
301328
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+
302386 /**
303387 * @deprecated Use {@link #debugFlags} instead.
304388 */
@@ -370,6 +454,39 @@ public BoxStoreBuilder initialDbFile(Factory<InputStream> initialDbFileFactory)
370454 return this ;
371455 }
372456
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+
373490 /**
374491 * Builds a {@link BoxStore} using any given configuration.
375492 */
0 commit comments