@@ -220,7 +220,8 @@ public static boolean isSyncServerAvailable() {
220
220
221
221
private final File directory ;
222
222
private final String canonicalPath ;
223
- private final long handle ;
223
+ /** Reference to the native store. Should probably get through {@link #getNativeStore()} instead. */
224
+ private long handle ;
224
225
private final Map <Class <?>, String > dbNameByClass = new HashMap <>();
225
226
private final Map <Class <?>, Integer > entityTypeIdByClass = new HashMap <>();
226
227
private final Map <Class <?>, EntityInfo <?>> propertiesByClass = new HashMap <>();
@@ -467,11 +468,12 @@ public static long sysProcStatusKb(String key) {
467
468
* @return 0 if the size could not be determined (does not throw unless this store was already closed)
468
469
*/
469
470
public long sizeOnDisk () {
470
- checkOpen ();
471
- return nativeSizeOnDisk (handle );
471
+ return nativeSizeOnDisk (getNativeStore ());
472
472
}
473
473
474
474
/**
475
+ * Closes this if this is finalized.
476
+ * <p>
475
477
* Explicitly call {@link #close()} instead to avoid expensive finalization.
476
478
*/
477
479
@ SuppressWarnings ("deprecation" ) // finalize()
@@ -481,8 +483,11 @@ protected void finalize() throws Throwable {
481
483
super .finalize ();
482
484
}
483
485
486
+ /**
487
+ * Verifies this has not been {@link #close() closed}.
488
+ */
484
489
private void checkOpen () {
485
- if (closed ) {
490
+ if (isClosed () ) {
486
491
throw new IllegalStateException ("Store is closed" );
487
492
}
488
493
}
@@ -533,13 +538,12 @@ <T> EntityInfo<T> getEntityInfo(Class<T> entityClass) {
533
538
*/
534
539
@ Internal
535
540
public Transaction beginTx () {
536
- checkOpen ();
537
541
// Because write TXs are typically not cached, initialCommitCount is not as relevant than for read TXs.
538
542
int initialCommitCount = commitCount ;
539
543
if (debugTxWrite ) {
540
544
System .out .println ("Begin TX with commit count " + initialCommitCount );
541
545
}
542
- long nativeTx = nativeBeginTx (handle );
546
+ long nativeTx = nativeBeginTx (getNativeStore () );
543
547
if (nativeTx == 0 ) throw new DbException ("Could not create native transaction" );
544
548
545
549
Transaction tx = new Transaction (this , nativeTx , initialCommitCount );
@@ -555,7 +559,6 @@ public Transaction beginTx() {
555
559
*/
556
560
@ Internal
557
561
public Transaction beginReadTx () {
558
- checkOpen ();
559
562
// initialCommitCount should be acquired before starting the tx. In race conditions, there is a chance the
560
563
// commitCount is already outdated. That's OK because it only gives a false positive for an TX being obsolete.
561
564
// In contrast, a false negative would make a TX falsely not considered obsolete, and thus readers would not be
@@ -565,7 +568,7 @@ public Transaction beginReadTx() {
565
568
if (debugTxRead ) {
566
569
System .out .println ("Begin read TX with commit count " + initialCommitCount );
567
570
}
568
- long nativeTx = nativeBeginReadTx (handle );
571
+ long nativeTx = nativeBeginReadTx (getNativeStore () );
569
572
if (nativeTx == 0 ) throw new DbException ("Could not create native read transaction" );
570
573
571
574
Transaction tx = new Transaction (this , nativeTx , initialCommitCount );
@@ -575,6 +578,9 @@ public Transaction beginReadTx() {
575
578
return tx ;
576
579
}
577
580
581
+ /**
582
+ * If this was {@link #close() closed}.
583
+ */
578
584
public boolean isClosed () {
579
585
return closed ;
580
586
}
@@ -584,8 +590,7 @@ public boolean isClosed() {
584
590
* If true the schema is not updated and write transactions are not possible.
585
591
*/
586
592
public boolean isReadOnly () {
587
- checkOpen ();
588
- return nativeIsReadOnly (handle );
593
+ return nativeIsReadOnly (getNativeStore ());
589
594
}
590
595
591
596
/**
@@ -621,7 +626,9 @@ public void close() {
621
626
}
622
627
if (handle != 0 ) { // failed before native handle was created?
623
628
nativeDelete (handle );
624
- // TODO set handle to 0 and check in native methods
629
+ // The Java API has open checks, but just in case re-set the handle so any native methods will
630
+ // not crash due to an invalid pointer.
631
+ handle = 0 ;
625
632
}
626
633
627
634
// When running the full unit test suite, we had 100+ threads before, hope this helps:
@@ -665,7 +672,7 @@ private void checkThreadTermination() {
665
672
* Note: If false is returned, any number of files may have been deleted before the failure happened.
666
673
*/
667
674
public boolean deleteAllFiles () {
668
- if (!closed ) {
675
+ if (!isClosed () ) {
669
676
throw new IllegalStateException ("Store must be closed" );
670
677
}
671
678
return deleteAllFiles (directory );
@@ -765,8 +772,7 @@ public static boolean deleteAllFiles(@Nullable File baseDirectoryOrNull, @Nullab
765
772
* </ul>
766
773
*/
767
774
public void removeAllObjects () {
768
- checkOpen ();
769
- nativeDropAllData (handle );
775
+ nativeDropAllData (getNativeStore ());
770
776
}
771
777
772
778
@ Internal
@@ -1049,8 +1055,7 @@ public <R> void callInTxAsync(final Callable<R> callable, @Nullable final TxCall
1049
1055
* @return String that is typically logged by the application.
1050
1056
*/
1051
1057
public String diagnose () {
1052
- checkOpen ();
1053
- return nativeDiagnose (handle );
1058
+ return nativeDiagnose (getNativeStore ());
1054
1059
}
1055
1060
1056
1061
/**
@@ -1069,13 +1074,11 @@ public long validate(long pageLimit, boolean checkLeafLevel) {
1069
1074
if (pageLimit < 0 ) {
1070
1075
throw new IllegalArgumentException ("pageLimit must be zero or positive" );
1071
1076
}
1072
- checkOpen ();
1073
- return nativeValidate (handle , pageLimit , checkLeafLevel );
1077
+ return nativeValidate (getNativeStore (), pageLimit , checkLeafLevel );
1074
1078
}
1075
1079
1076
1080
public int cleanStaleReadTransactions () {
1077
- checkOpen ();
1078
- return nativeCleanStaleReadTransactions (handle );
1081
+ return nativeCleanStaleReadTransactions (getNativeStore ());
1079
1082
}
1080
1083
1081
1084
/**
@@ -1090,11 +1093,6 @@ public void closeThreadResources() {
1090
1093
// activeTx is cleaned up in finally blocks, so do not free them here
1091
1094
}
1092
1095
1093
- @ Internal
1094
- long internalHandle () {
1095
- return handle ;
1096
- }
1097
-
1098
1096
/**
1099
1097
* A {@link io.objectbox.reactive.DataObserver} can be subscribed to data changes using the returned builder.
1100
1098
* The observer is supplied via {@link SubscriptionBuilder#observer(DataObserver)} and will be notified once a
@@ -1146,8 +1144,7 @@ public String startObjectBrowser() {
1146
1144
@ Nullable
1147
1145
public String startObjectBrowser (int port ) {
1148
1146
verifyObjectBrowserNotRunning ();
1149
- checkOpen ();
1150
- String url = nativeStartObjectBrowser (handle , null , port );
1147
+ String url = nativeStartObjectBrowser (getNativeStore (), null , port );
1151
1148
if (url != null ) {
1152
1149
objectBrowserPort = port ;
1153
1150
}
@@ -1158,14 +1155,13 @@ public String startObjectBrowser(int port) {
1158
1155
@ Nullable
1159
1156
public String startObjectBrowser (String urlToBindTo ) {
1160
1157
verifyObjectBrowserNotRunning ();
1161
- checkOpen ();
1162
1158
int port ;
1163
1159
try {
1164
1160
port = new URL (urlToBindTo ).getPort (); // Gives -1 if not available
1165
1161
} catch (MalformedURLException e ) {
1166
1162
throw new RuntimeException ("Can not start Object Browser at " + urlToBindTo , e );
1167
1163
}
1168
- String url = nativeStartObjectBrowser (handle , urlToBindTo , 0 );
1164
+ String url = nativeStartObjectBrowser (getNativeStore () , urlToBindTo , 0 );
1169
1165
if (url != null ) {
1170
1166
objectBrowserPort = port ;
1171
1167
}
@@ -1178,8 +1174,7 @@ public synchronized boolean stopObjectBrowser() {
1178
1174
throw new IllegalStateException ("ObjectBrowser has not been started before" );
1179
1175
}
1180
1176
objectBrowserPort = 0 ;
1181
- checkOpen ();
1182
- return nativeStopObjectBrowser (handle );
1177
+ return nativeStopObjectBrowser (getNativeStore ());
1183
1178
}
1184
1179
1185
1180
@ Experimental
@@ -1204,8 +1199,7 @@ private void verifyObjectBrowserNotRunning() {
1204
1199
* This for example allows central error handling or special logging for database-related exceptions.
1205
1200
*/
1206
1201
public void setDbExceptionListener (@ Nullable DbExceptionListener dbExceptionListener ) {
1207
- checkOpen ();
1208
- nativeSetDbExceptionListener (handle , dbExceptionListener );
1202
+ nativeSetDbExceptionListener (getNativeStore (), dbExceptionListener );
1209
1203
}
1210
1204
1211
1205
@ Internal
@@ -1234,18 +1228,19 @@ public TxCallback<?> internalFailedReadTxAttemptCallback() {
1234
1228
}
1235
1229
1236
1230
void setDebugFlags (int debugFlags ) {
1237
- checkOpen ();
1238
- nativeSetDebugFlags (handle , debugFlags );
1231
+ nativeSetDebugFlags (getNativeStore (), debugFlags );
1239
1232
}
1240
1233
1241
1234
long panicModeRemoveAllObjects (int entityId ) {
1242
- checkOpen ();
1243
- return nativePanicModeRemoveAllObjects (handle , entityId );
1235
+ return nativePanicModeRemoveAllObjects (getNativeStore (), entityId );
1244
1236
}
1245
1237
1246
1238
/**
1247
- * If you want to use the same ObjectBox store using the C API, e.g. via JNI, this gives the required pointer,
1248
- * which you have to pass on to obx_store_wrap().
1239
+ * Gets the reference to the native store. Can be used with the C API to use the same store, e.g. via JNI, by
1240
+ * passing it on to {@code obx_store_wrap()}.
1241
+ * <p>
1242
+ * Throws if the store is closed.
1243
+ * <p>
1249
1244
* The procedure is like this:<br>
1250
1245
* 1) you create a BoxStore on the Java side<br>
1251
1246
* 2) you call this method to get the native store pointer<br>
0 commit comments