Implement backuppable class

This commit is contained in:
Andrea Cavalli 2022-08-15 23:07:17 +02:00
parent 8b6f1dfe87
commit ddd71d3b72
10 changed files with 237 additions and 4 deletions

View File

@ -0,0 +1,57 @@
package it.cavallium.dbengine.client;
import java.util.concurrent.atomic.AtomicInteger;
import reactor.core.publisher.Mono;
import reactor.core.publisher.SignalType;
public abstract class Backuppable implements IBackuppable {
public enum State {
RUNNING, PAUSING, PAUSED, RESUMING, STOPPED
}
private final AtomicInteger state = new AtomicInteger();
@Override
public final Mono<Void> pauseForBackup() {
return Mono.defer(() -> {
if (state.compareAndSet(State.RUNNING.ordinal(), State.PAUSING.ordinal())) {
return onPauseForBackup().doFinally(type -> state.compareAndSet(State.PAUSING.ordinal(),
type == SignalType.ON_ERROR ? State.RUNNING.ordinal() : State.PAUSED.ordinal()
));
} else {
return Mono.empty();
}
});
}
@Override
public final Mono<Void> resumeAfterBackup() {
return Mono.defer(() -> {
if (state.compareAndSet(State.PAUSED.ordinal(), State.RESUMING.ordinal())) {
return onResumeAfterBackup().doFinally(type -> state.compareAndSet(State.RESUMING.ordinal(),
type == SignalType.ON_ERROR ? State.PAUSED.ordinal() : State.RUNNING.ordinal()
));
} else {
return Mono.empty();
}
});
}
@Override
public final boolean isPaused() {
return state.get() == State.PAUSED.ordinal();
}
public final State getState() {
return State.values()[state.get()];
}
protected abstract Mono<Void> onPauseForBackup();
protected abstract Mono<Void> onResumeAfterBackup();
public final void setStopped() {
state.set(State.STOPPED.ordinal());
}
}

View File

@ -0,0 +1,12 @@
package it.cavallium.dbengine.client;
import reactor.core.publisher.Mono;
public interface IBackuppable {
Mono<Void> pauseForBackup();
Mono<Void> resumeAfterBackup();
boolean isPaused();
}

View File

@ -4,6 +4,7 @@ import com.google.common.primitives.Ints;
import com.google.common.primitives.Longs;
import io.micrometer.core.instrument.MeterRegistry;
import io.netty5.buffer.api.BufferAllocator;
import it.cavallium.dbengine.client.IBackuppable;
import it.cavallium.dbengine.client.MemoryStats;
import it.cavallium.dbengine.database.collections.DatabaseInt;
import it.cavallium.dbengine.database.collections.DatabaseLong;
@ -14,7 +15,8 @@ import org.jetbrains.annotations.Nullable;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
public interface LLKeyValueDatabase extends LLSnapshottable, LLKeyValueDatabaseStructure, DatabaseProperties {
public interface LLKeyValueDatabase extends LLSnapshottable, LLKeyValueDatabaseStructure, DatabaseProperties,
IBackuppable {
Mono<? extends LLSingleton> getSingleton(byte[] singletonListColumnName, byte[] name, byte @Nullable[] defaultValue);

View File

@ -1,6 +1,7 @@
package it.cavallium.dbengine.database;
import com.google.common.collect.Multimap;
import it.cavallium.dbengine.client.IBackuppable;
import it.cavallium.dbengine.client.query.current.data.NoSort;
import it.cavallium.dbengine.client.query.current.data.Query;
import it.cavallium.dbengine.client.query.current.data.QueryParams;
@ -16,7 +17,7 @@ import org.jetbrains.annotations.Nullable;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
public interface LLLuceneIndex extends LLSnapshottable, SafeCloseable {
public interface LLLuceneIndex extends LLSnapshottable, IBackuppable, SafeCloseable {
String getLuceneIndexName();

View File

@ -1,6 +1,8 @@
package it.cavallium.dbengine.database;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
import it.cavallium.dbengine.client.IBackuppable;
import it.cavallium.dbengine.rpc.current.data.IndicizerAnalyzers;
import it.cavallium.dbengine.rpc.current.data.IndicizerSimilarities;
import it.cavallium.dbengine.client.query.current.data.Query;
@ -242,4 +244,24 @@ public class LLMultiLuceneIndex implements LLLuceneIndex {
})
.then();
}
@Override
public Mono<Void> pauseForBackup() {
return Mono.whenDelayError(Iterables.transform(this.luceneIndicesSet, IBackuppable::pauseForBackup));
}
@Override
public Mono<Void> resumeAfterBackup() {
return Mono.whenDelayError(Iterables.transform(this.luceneIndicesSet, IBackuppable::resumeAfterBackup));
}
@Override
public boolean isPaused() {
for (LLLuceneIndex llLuceneIndex : this.luceneIndicesSet) {
if (llLuceneIndex.isPaused()) {
return true;
}
}
return false;
}
}

View File

@ -12,6 +12,7 @@ import io.micrometer.core.instrument.Timer;
import io.netty5.buffer.api.BufferAllocator;
import io.netty5.util.internal.PlatformDependent;
import it.cavallium.data.generator.nativedata.NullableString;
import it.cavallium.dbengine.client.Backuppable;
import it.cavallium.dbengine.client.MemoryStats;
import it.cavallium.dbengine.database.ColumnProperty;
import it.cavallium.dbengine.database.ColumnUtils;
@ -98,7 +99,7 @@ import reactor.core.publisher.Mono;
import reactor.core.scheduler.Scheduler;
import reactor.core.scheduler.Schedulers;
public class LLLocalKeyValueDatabase implements LLKeyValueDatabase {
public class LLLocalKeyValueDatabase extends Backuppable implements LLKeyValueDatabase {
private static final boolean DELETE_LOG_FILES = false;
private static final boolean FOLLOW_ROCKSDB_OPTIMIZATIONS = true;
@ -687,6 +688,16 @@ public class LLLocalKeyValueDatabase implements LLKeyValueDatabase {
}).subscribeOn(dbWScheduler);
}
@Override
protected Mono<Void> onPauseForBackup() {
return pauseWrites();
}
@Override
protected Mono<Void> onResumeAfterBackup() {
return resumeWrites();
}
private record RocksLevelOptions(CompressionType compressionType, CompressionOptions compressionOptions) {}
private RocksLevelOptions getRocksLevelOptions(DatabaseLevel levelOptions, RocksDBRefs refs) {
var compressionType = levelOptions.compression().getType();
@ -1617,6 +1628,22 @@ public class LLLocalKeyValueDatabase implements LLKeyValueDatabase {
.subscribeOn(dbWScheduler);
}
private Mono<Void> pauseWrites() {
return Mono.<Void>fromCallable(() -> {
db.pauseBackgroundWork();
db.disableFileDeletions();
return null;
}).subscribeOn(dbWScheduler);
}
private Mono<Void> resumeWrites() {
return Mono.<Void>fromCallable(() -> {
db.continueBackgroundWork();
db.enableFileDeletions(false);
return null;
}).subscribeOn(dbWScheduler);
}
/**
* Call this method ONLY AFTER flushing completely a db and closing it!
*/

View File

@ -14,6 +14,8 @@ import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Timer;
import it.cavallium.dbengine.client.Backuppable;
import it.cavallium.dbengine.client.IBackuppable;
import it.cavallium.dbengine.client.query.QueryParser;
import it.cavallium.dbengine.client.query.current.data.Query;
import it.cavallium.dbengine.client.query.current.data.QueryParams;
@ -82,7 +84,7 @@ import reactor.core.publisher.SignalType;
import reactor.core.scheduler.Scheduler;
import reactor.core.scheduler.Schedulers;
public class LLLocalLuceneIndex extends SimpleResource implements LLLuceneIndex, LuceneCloseable {
public class LLLocalLuceneIndex extends SimpleResource implements IBackuppable, LLLuceneIndex, LuceneCloseable {
protected static final Logger logger = LogManager.getLogger(LLLocalLuceneIndex.class);
@ -138,6 +140,7 @@ public class LLLocalLuceneIndex extends SimpleResource implements LLLuceneIndex,
private final Similarity luceneSimilarity;
private final LuceneRocksDBManager rocksDBManager;
private final Directory directory;
private final LuceneBackuppable backuppable;
private final boolean lowMemory;
private final Phaser activeTasks = new Phaser(1);
@ -280,6 +283,8 @@ public class LLLocalLuceneIndex extends SimpleResource implements LLLuceneIndex,
var commitMillis = luceneOptions.commitDebounceTime().toMillis();
luceneHeavyTasksScheduler.schedulePeriodically(this::scheduledCommit, commitMillis, commitMillis,
TimeUnit.MILLISECONDS);
this.backuppable = new LuceneBackuppable();
}
private Similarity getLuceneSimilarity() {
@ -848,4 +853,42 @@ public class LLLocalLuceneIndex extends SimpleResource implements LLLuceneIndex,
public int hashCode() {
return shardName.hashCode();
}
@Override
public Mono<Void> pauseForBackup() {
return backuppable.pauseForBackup();
}
@Override
public Mono<Void> resumeAfterBackup() {
return backuppable.resumeAfterBackup();
}
@Override
public boolean isPaused() {
return backuppable.isPaused();
}
private class LuceneBackuppable extends Backuppable {
private LLSnapshot snapshot;
@Override
protected Mono<Void> onPauseForBackup() {
return LLLocalLuceneIndex.this.takeSnapshot().doOnSuccess(snapshot -> {
if (snapshot == null) {
logger.error("Can't pause index \"{}\" because snapshots are not enabled!", shardName);
}
this.snapshot = snapshot;
}).then();
}
@Override
protected Mono<Void> onResumeAfterBackup() {
if (snapshot == null) {
return Mono.empty();
}
return LLLocalLuceneIndex.this.releaseSnapshot(snapshot);
}
}
}

View File

@ -3,9 +3,11 @@ package it.cavallium.dbengine.database.disk;
import static it.cavallium.dbengine.client.UninterruptibleScheduler.uninterruptibleScheduler;
import static it.cavallium.dbengine.lucene.LuceneUtils.luceneScheduler;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
import io.micrometer.core.instrument.MeterRegistry;
import io.netty5.util.Send;
import it.cavallium.dbengine.client.IBackuppable;
import it.cavallium.dbengine.client.query.QueryParser;
import it.cavallium.dbengine.client.query.current.data.NoSort;
import it.cavallium.dbengine.client.query.current.data.Query;
@ -415,4 +417,24 @@ public class LLLocalMultiLuceneIndex extends SimpleResource implements LLLuceneI
public boolean isLowMemoryMode() {
return lowMemory;
}
@Override
public Mono<Void> pauseForBackup() {
return Mono.whenDelayError(Iterables.transform(this.luceneIndicesSet, IBackuppable::pauseForBackup));
}
@Override
public Mono<Void> resumeAfterBackup() {
return Mono.whenDelayError(Iterables.transform(this.luceneIndicesSet, IBackuppable::resumeAfterBackup));
}
@Override
public boolean isPaused() {
for (LLLuceneIndex llLuceneIndex : this.luceneIndicesSet) {
if (llLuceneIndex.isPaused()) {
return true;
}
}
return false;
}
}

View File

@ -213,4 +213,19 @@ public class LLMemoryKeyValueDatabase implements LLKeyValueDatabase {
.fromCallable(() -> snapshots.remove(snapshot.getSequenceNumber()))
.then();
}
@Override
public Mono<Void> pauseForBackup() {
return Mono.empty();
}
@Override
public Mono<Void> resumeAfterBackup() {
return Mono.empty();
}
@Override
public boolean isPaused() {
return false;
}
}

View File

@ -231,6 +231,7 @@ public class LLQuicConnection implements LLDatabaseConnection {
.cast(GeneratedEntityId.class)
.map(GeneratedEntityId::id)
.map(id -> new LLKeyValueDatabase() {
@Override
public Mono<? extends LLSingleton> getSingleton(byte[] singletonListColumnName,
byte[] name,
@ -423,6 +424,21 @@ public class LLQuicConnection implements LLDatabaseConnection {
public Mono<Void> releaseSnapshot(LLSnapshot snapshot) {
return null;
}
@Override
public Mono<Void> pauseForBackup() {
return Mono.empty();
}
@Override
public Mono<Void> resumeAfterBackup() {
return Mono.empty();
}
@Override
public boolean isPaused() {
return false;
}
});
}
@ -446,6 +462,7 @@ public class LLQuicConnection implements LLDatabaseConnection {
.cast(GeneratedEntityId.class)
.map(GeneratedEntityId::id)
.map(id -> new LLLuceneIndex() {
@Override
public String getLuceneIndexName() {
return clusterName;
@ -543,6 +560,21 @@ public class LLQuicConnection implements LLDatabaseConnection {
public Mono<Void> releaseSnapshot(LLSnapshot snapshot) {
return null;
}
@Override
public Mono<Void> pauseForBackup() {
return null;
}
@Override
public Mono<Void> resumeAfterBackup() {
return null;
}
@Override
public boolean isPaused() {
return false;
}
});
}