Skip to content

Commit 0deebdd

Browse files
committed
fix: exception thrown in a transaction could cause issue with page reloading
1 parent 0fce213 commit 0deebdd

2 files changed

Lines changed: 85 additions & 11 deletions

File tree

engine/src/main/java/com/arcadedb/engine/PageManager.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ public void deleteFile(final Database database, final int fileId) {
176176
private int getMostRecentVersionOfPage(final PageId pageId, final int pageSize) throws IOException {
177177
CachedPage page = readCache.get(pageId);
178178
if (page == null)
179-
page = loadPage(pageId, pageSize, false, false);
179+
page = loadPage(pageId, pageSize, false, true);
180180

181181
if (page != null)
182182
return page.getVersion();

engine/src/test/java/com/arcadedb/ACIDTransactionTest.java

Lines changed: 84 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@
2222
import com.arcadedb.database.DatabaseInternal;
2323
import com.arcadedb.database.Document;
2424
import com.arcadedb.database.MutableDocument;
25+
import com.arcadedb.database.RID;
2526
import com.arcadedb.database.bucketselectionstrategy.ThreadBucketSelectionStrategy;
2627
import com.arcadedb.engine.WALException;
2728
import com.arcadedb.engine.WALFile;
29+
import com.arcadedb.exception.DuplicatedKeyException;
2830
import com.arcadedb.exception.NeedRetryException;
2931
import com.arcadedb.exception.TransactionException;
3032
import com.arcadedb.graph.MutableVertex;
@@ -37,16 +39,11 @@
3739
import com.arcadedb.schema.VertexType;
3840
import org.junit.jupiter.api.Test;
3941

40-
import java.io.File;
41-
import java.io.IOException;
42-
import java.util.ArrayList;
43-
import java.util.Calendar;
44-
import java.util.Iterator;
45-
import java.util.List;
46-
import java.util.concurrent.Callable;
47-
import java.util.concurrent.atomic.AtomicBoolean;
48-
import java.util.concurrent.atomic.AtomicInteger;
49-
import java.util.logging.Level;
42+
import java.io.*;
43+
import java.util.*;
44+
import java.util.concurrent.*;
45+
import java.util.concurrent.atomic.*;
46+
import java.util.logging.*;
5047

5148
import static org.assertj.core.api.Assertions.assertThat;
5249
import static org.assertj.core.api.Assertions.fail;
@@ -457,6 +454,83 @@ public void testAsyncEdges() {
457454
database.transaction(() -> assertThat(database.countType("Arc", true)).isEqualTo(TOT - 1));
458455
}
459456

457+
@Test
458+
public void testExceptionInsideTransaction() {
459+
final Database db = database;
460+
461+
final int TOT = 100;
462+
463+
final VertexType type = database.getSchema().getOrCreateVertexType("Node");
464+
//type.getOrCreateProperty("id", Type.STRING).getOrCreateIndex(Schema.INDEX_TYPE.LSM_TREE, true);
465+
466+
final AtomicInteger thrownExceptions = new AtomicInteger(0);
467+
final AtomicInteger caughtExceptions = new AtomicInteger(0);
468+
final AtomicInteger committed = new AtomicInteger(0);
469+
470+
final RID[] rid = new RID[1];
471+
472+
database.transaction(() -> {
473+
final MutableVertex v = db.newVertex("Node");
474+
v.set("id", 0);
475+
v.set("name", "Exception(al)");
476+
v.set("surname", "Test");
477+
v.save();
478+
rid[0] = v.getIdentity();
479+
});
480+
481+
final int CONCURRENT_THREADS = 4;
482+
483+
// SPAWN ALL THE THREADS
484+
final Thread[] threads = new Thread[CONCURRENT_THREADS];
485+
for (int i = 0; i < CONCURRENT_THREADS; i++) {
486+
threads[i] = new Thread(() -> {
487+
for (int k = 0; k < TOT; ++k) {
488+
final int id = k;
489+
490+
try {
491+
database.transaction(() -> {
492+
MutableVertex v = rid[0].asVertex().modify();
493+
v.set("id", id);
494+
v.save();
495+
496+
if ((id + 1) % 100 == 0) {
497+
thrownExceptions.incrementAndGet();
498+
// System.out.println("Simulating exception at id=" + id + " (thread=" + Thread.currentThread().getName() + ")");
499+
//throw new DuplicatedKeyException("indexName", "key", rid[0]);
500+
throw new RuntimeException("Test exception at " + id);
501+
}
502+
});
503+
committed.incrementAndGet();
504+
505+
} catch (Exception e) {
506+
caughtExceptions.incrementAndGet();
507+
// System.out.println("Caught: " + e.getMessage() + " (id=" + id + ", thread=" + Thread.currentThread().getName() + ")");
508+
}
509+
}
510+
511+
});
512+
threads[i].start();
513+
}
514+
515+
// WAIT FOR ALL THE THREADS
516+
for (int i = 0; i < CONCURRENT_THREADS; i++)
517+
try {
518+
threads[i].join();
519+
} catch (InterruptedException e) {
520+
// IGNORE IT
521+
}
522+
523+
assertThat(database.countType("Node", true)).isEqualTo(1);
524+
525+
assertThat(committed.get()).isGreaterThan(0);
526+
assertThat(thrownExceptions.get()).isGreaterThan(0);
527+
assertThat(caughtExceptions.get()).isGreaterThan(0);
528+
assertThat(committed.get() + caughtExceptions.get()).isEqualTo(TOT * CONCURRENT_THREADS);
529+
530+
// System.out.println(
531+
// "Committed: " + committed.get() + ", Thrown: " + thrownExceptions.get() + ", Caught: " + caughtExceptions.get());
532+
}
533+
460534
@Test
461535
public void testDeleteOverwriteCompositeKeyInTx() {
462536
database.transaction(() ->

0 commit comments

Comments
 (0)