Skip to content

Commit

Permalink
feat: disable backup lock for embedded massive insertion only gaining…
Browse files Browse the repository at this point in the history
… around 30% improvement in speed (#1852)

Tested LocalDatabaseBenchmark on my MacBook Pro 2019 and it's able to insert 4.3M rec/sec (multi-threads, 1 property only, 1 unique index). With default settings (backup enabled = true) the performance dropped to 3.2M rec/sec

Added new global cfg:

BACKUP_ENABLED("arcadedb.backup.enabled")
  • Loading branch information
lvca authored Dec 5, 2024
1 parent 52e0757 commit 277c558
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 8 deletions.
6 changes: 5 additions & 1 deletion engine/src/main/java/com/arcadedb/GlobalConfiguration.java
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public Object call(final Object value) {
}, null, Set.of("default", "high-performance", "low-ram", "low-cpu")),

TEST("arcadedb.test", SCOPE.JVM,
"Tells if it is running in test mode. This enables the calling of callbacks for testing purpose ", Boolean.class, false),
"Tells if it is running in test mode. This enables the calling of callbacks for testing purpose", Boolean.class, false),

MAX_PAGE_RAM("arcadedb.maxPageRAM", SCOPE.DATABASE, "Maximum amount of pages (in MB) to keep in RAM", Long.class, 4 * 1024, // 4GB
new Callable<>() {
Expand Down Expand Up @@ -235,6 +235,10 @@ public Object call(final Object value) {
"Maximum amount of milliseconds to compute a random number to wait for the next retry. This setting is helpful in case of high concurrency on the same pages (multi-thread insertion over the same bucket)",
Integer.class, 100),

BACKUP_ENABLED("arcadedb.backup.enabled", SCOPE.DATABASE,
"Allow a database to be backup. Disabling backup gives a huge boost in performance because no lock will be used for every operations",
Boolean.class, true),

// SQL
SQL_STATEMENT_CACHE("arcadedb.sqlStatementCache", SCOPE.DATABASE, "Maximum number of parsed statements to keep in cache",
Integer.class, 300),
Expand Down
10 changes: 6 additions & 4 deletions engine/src/main/java/com/arcadedb/database/LocalDatabase.java
Original file line number Diff line number Diff line change
Expand Up @@ -1409,7 +1409,7 @@ public SecurityManager getSecurity() {
*/
@Override
public <RET> RET executeInReadLock(final Callable<RET> callable) {
final ReentrantReadWriteLock.ReadLock stamp = readLock();
final ReentrantReadWriteLock.ReadLock readLock = readLock();
try {

return callable.call();
Expand All @@ -1426,7 +1426,7 @@ public <RET> RET executeInReadLock(final Callable<RET> callable) {
throw new DatabaseOperationException("Error during read lock", e);

} finally {
readUnlock(stamp);
readUnlock(readLock);
}
}

Expand All @@ -1435,7 +1435,7 @@ public <RET> RET executeInReadLock(final Callable<RET> callable) {
*/
@Override
public <RET> RET executeInWriteLock(final Callable<RET> callable) {
final ReentrantReadWriteLock.WriteLock stamp = writeLock();
final ReentrantReadWriteLock.WriteLock writeLock = writeLock();
try {

return callable.call();
Expand All @@ -1452,7 +1452,7 @@ public <RET> RET executeInWriteLock(final Callable<RET> callable) {
throw new DatabaseOperationException("Error during write lock", e);

} finally {
writeUnlock(stamp);
writeUnlock(writeLock);
}
}

Expand Down Expand Up @@ -1772,6 +1772,7 @@ private void checkForRecovery() throws IOException {
private void openInternal() {
try {
DatabaseContext.INSTANCE.init(this);
setLockingEnabled(configuration.getValueAsBoolean(GlobalConfiguration.BACKUP_ENABLED));

fileManager = new FileManager(databasePath, mode, SUPPORTED_FILE_EXT);
transactionManager = new TransactionManager(wrappedDatabaseInstance);
Expand Down Expand Up @@ -1854,4 +1855,5 @@ private void delayBetweenRetries(final int retryDelay) {
}
}
}

}
17 changes: 16 additions & 1 deletion engine/src/main/java/com/arcadedb/utility/RWLockContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,13 @@
import java.util.concurrent.locks.*;

public class RWLockContext {
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
private boolean enableLocking = true;

protected ReentrantReadWriteLock.ReadLock readLock() {
if (!enableLocking)
return null;

final ReentrantReadWriteLock.ReadLock rl = lock.readLock();
rl.lock();
return rl;
Expand All @@ -38,6 +42,9 @@ protected void readUnlock(final ReentrantReadWriteLock.ReadLock rl) {
}

protected ReentrantReadWriteLock.WriteLock writeLock() {
if (!enableLocking)
return null;

final ReentrantReadWriteLock.WriteLock wl = lock.writeLock();
wl.lock();
return wl;
Expand Down Expand Up @@ -87,4 +94,12 @@ public <RET> RET executeInWriteLock(final Callable<RET> callable) {
writeUnlock(wl);
}
}

protected void setLockingEnabled(final boolean enabled) {
this.enableLocking = enabled;
}

protected boolean isLockingEnabled() {
return enableLocking;
}
}
6 changes: 4 additions & 2 deletions engine/src/test/java/performance/LocalDatabaseBenchmark.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,11 @@ public static void main(String[] args) {

private void endTest() {
database.close();
GlobalConfiguration.resetAll();
}

private void beginTest() {
GlobalConfiguration.BACKUP_ENABLED.setValue(false);
if (new DatabaseFactory(DATABASE_NAME).exists())
new DatabaseFactory(DATABASE_NAME).open().drop();
database = new DatabaseFactory(DATABASE_NAME).create();
Expand Down Expand Up @@ -153,8 +155,8 @@ private void querySQL() {
long begin = System.currentTimeMillis();
for (int i = 0; i < TOTAL * CONCURRENT_THREADS; i++) {
assertThat(database.query("sql",
"select from User where id = ? and id = ? and id = ? and id = ? and id = ? and id = ? and id = ? and id = ? and id = ? and id = ?",
i, i, i, i, i, i, i, i, i, i).toVertices().size()).isEqualTo(1);
"select from User where id = ? and id = ? and id = ? and id = ? and id = ? and id = ? and id = ? and id = ? and id = ? and id = ?",
i, i, i, i, i, i, i, i, i, i).toVertices().size()).isEqualTo(1);
}
System.out.println("SQL " + (System.currentTimeMillis() - begin) + "ms");
}
Expand Down

0 comments on commit 277c558

Please sign in to comment.