Skip to content

Commit b75c2e5

Browse files
committed
BoxStore fix: close resources and remove path from openFiles if an exception is thrown in constructor, add test usePreviousCommitAfterFileCorruptException()
1 parent fd61d0f commit b75c2e5

File tree

2 files changed

+60
-34
lines changed

2 files changed

+60
-34
lines changed

objectbox-java/src/main/java/io/objectbox/BoxStore.java

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -225,47 +225,52 @@ public static boolean isObjectBrowserAvailable() {
225225
canonicalPath = getCanonicalPath(directory);
226226
verifyNotAlreadyOpen(canonicalPath);
227227

228-
handle = nativeCreateWithFlatOptions(builder.buildFlatStoreOptions(canonicalPath), builder.model);
229-
int debugFlags = builder.debugFlags;
230-
if (debugFlags != 0) {
231-
debugTxRead = (debugFlags & DebugFlags.LOG_TRANSACTIONS_READ) != 0;
232-
debugTxWrite = (debugFlags & DebugFlags.LOG_TRANSACTIONS_WRITE) != 0;
233-
} else {
234-
debugTxRead = debugTxWrite = false;
235-
}
236-
debugRelations = builder.debugRelations;
228+
try {
229+
handle = nativeCreateWithFlatOptions(builder.buildFlatStoreOptions(canonicalPath), builder.model);
230+
int debugFlags = builder.debugFlags;
231+
if (debugFlags != 0) {
232+
debugTxRead = (debugFlags & DebugFlags.LOG_TRANSACTIONS_READ) != 0;
233+
debugTxWrite = (debugFlags & DebugFlags.LOG_TRANSACTIONS_WRITE) != 0;
234+
} else {
235+
debugTxRead = debugTxWrite = false;
236+
}
237+
debugRelations = builder.debugRelations;
237238

238-
for (EntityInfo<?> entityInfo : builder.entityInfoList) {
239-
try {
240-
dbNameByClass.put(entityInfo.getEntityClass(), entityInfo.getDbName());
241-
int entityId = nativeRegisterEntityClass(handle, entityInfo.getDbName(), entityInfo.getEntityClass());
242-
entityTypeIdByClass.put(entityInfo.getEntityClass(), entityId);
243-
classByEntityTypeId.put(entityId, entityInfo.getEntityClass());
244-
propertiesByClass.put(entityInfo.getEntityClass(), entityInfo);
245-
for (Property<?> property : entityInfo.getAllProperties()) {
246-
if (property.customType != null) {
247-
if (property.converterClass == null) {
248-
throw new RuntimeException("No converter class for custom type of " + property);
239+
for (EntityInfo<?> entityInfo : builder.entityInfoList) {
240+
try {
241+
dbNameByClass.put(entityInfo.getEntityClass(), entityInfo.getDbName());
242+
int entityId = nativeRegisterEntityClass(handle, entityInfo.getDbName(), entityInfo.getEntityClass());
243+
entityTypeIdByClass.put(entityInfo.getEntityClass(), entityId);
244+
classByEntityTypeId.put(entityId, entityInfo.getEntityClass());
245+
propertiesByClass.put(entityInfo.getEntityClass(), entityInfo);
246+
for (Property<?> property : entityInfo.getAllProperties()) {
247+
if (property.customType != null) {
248+
if (property.converterClass == null) {
249+
throw new RuntimeException("No converter class for custom type of " + property);
250+
}
251+
nativeRegisterCustomType(handle, entityId, 0, property.dbName, property.converterClass,
252+
property.customType);
249253
}
250-
nativeRegisterCustomType(handle, entityId, 0, property.dbName, property.converterClass,
251-
property.customType);
252254
}
255+
} catch (RuntimeException e) {
256+
throw new RuntimeException("Could not setup up entity " + entityInfo.getEntityClass(), e);
253257
}
254-
} catch (RuntimeException e) {
255-
throw new RuntimeException("Could not setup up entity " + entityInfo.getEntityClass(), e);
256258
}
257-
}
258-
int size = classByEntityTypeId.size();
259-
allEntityTypeIds = new int[size];
260-
long[] entityIdsLong = classByEntityTypeId.keys();
261-
for (int i = 0; i < size; i++) {
262-
allEntityTypeIds[i] = (int) entityIdsLong[i];
263-
}
259+
int size = classByEntityTypeId.size();
260+
allEntityTypeIds = new int[size];
261+
long[] entityIdsLong = classByEntityTypeId.keys();
262+
for (int i = 0; i < size; i++) {
263+
allEntityTypeIds[i] = (int) entityIdsLong[i];
264+
}
264265

265-
objectClassPublisher = new ObjectClassPublisher(this);
266+
objectClassPublisher = new ObjectClassPublisher(this);
266267

267-
failedReadTxAttemptCallback = builder.failedReadTxAttemptCallback;
268-
queryAttempts = Math.max(builder.queryAttempts, 1);
268+
failedReadTxAttemptCallback = builder.failedReadTxAttemptCallback;
269+
queryAttempts = Math.max(builder.queryAttempts, 1);
270+
} catch (RuntimeException runtimeException) {
271+
close(); // Proper clean up, e.g. delete native handle, remove this path from openFiles
272+
throw runtimeException;
273+
}
269274
}
270275

271276
static String getCanonicalPath(File directory) {

tests/objectbox-java-test/src/test/java/io/objectbox/BoxStoreBuilderTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,27 @@ public void usePreviousCommitWithCorruptFile() throws IOException {
183183
assertTrue(store.deleteAllFiles());
184184
}
185185

186+
@Test
187+
public void usePreviousCommitAfterFileCorruptException() throws IOException {
188+
File dir = prepareTempDir("object-store-test-corrupted");
189+
prepareBadDataFile(dir);
190+
builder = BoxStoreBuilder.createDebugWithoutModel().directory(dir);
191+
builder.validateOnOpen(ValidateOnOpenMode.Full);
192+
try {
193+
store = builder.build();
194+
fail("Should have thrown");
195+
} catch (FileCorruptException e) {
196+
builder.usePreviousCommit();
197+
store = builder.build();
198+
}
199+
200+
String diagnoseString = store.diagnose();
201+
assertTrue(diagnoseString.contains("entries=2"));
202+
store.validate(0, true);
203+
store.close();
204+
assertTrue(store.deleteAllFiles());
205+
}
206+
186207
private File prepareBadDataFile(File dir) throws IOException {
187208
assertTrue(dir.mkdir());
188209
File badDataFile = new File(dir, "data.mdb");

0 commit comments

Comments
 (0)