diff --git a/pom.xml b/pom.xml
index 3b1c9ed..7911d47 100644
--- a/pom.xml
+++ b/pom.xml
@@ -16,7 +16,7 @@
9.7.0
8.5.3
5.9.0
- 1.0.10
+ 1.0.12
@@ -364,14 +364,6 @@
src/test/java
-
-
- ../src/main/libs
-
- **/*.jar
-
-
-
kr.motd.maven
@@ -390,7 +382,7 @@
maven-compiler-plugin
3.11.0
- 17
+ 21
io.soabase.record-builder
@@ -401,7 +393,9 @@
io.soabase.recordbuilder.processor.RecordBuilderProcessor
-
+
+ 21
+
it.cavallium
@@ -535,4 +529,80 @@
+
+
+ repair
+
+ false
+
+ dbengine.build
+ repair
+
+
+
+
+
+ org.codehaus.mojo
+ build-helper-maven-plugin
+ 3.4.0
+
+
+ add-source
+ generate-sources
+
+ add-source
+
+
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+ 3.6.0
+
+
+ jar-with-dependencies
+
+
+
+ it.cavallium.dbengine.repair.Repair
+
+
+
+
+
+ make-assembly
+ package
+
+ single
+
+
+
+
+
+
+
+ src/repair/resources
+
+
+
+
+
+ org.apache.logging.log4j
+ log4j-slf4j2-impl
+ 2.20.0
+
+
+ com.lmax
+ disruptor
+ 3.4.4
+
+
+
+
diff --git a/src/main/data-generator/quic-rpc.yaml b/src/main/data-generator/quic-rpc.yaml
index df09519..afee9c9 100644
--- a/src/main/data-generator/quic-rpc.yaml
+++ b/src/main/data-generator/quic-rpc.yaml
@@ -255,6 +255,8 @@ baseTypesData:
columnOptions: NamedColumnOptions[]
logPath: -String
walPath: -String
+ openAsSecondary: boolean
+ secondaryDirectoryName: -String
# Remember to update ColumnOptions common getters
DefaultColumnOptions:
data:
diff --git a/src/main/java/it/cavallium/dbengine/client/BadBlock.java b/src/main/java/it/cavallium/dbengine/client/BadBlock.java
deleted file mode 100644
index 1edfdbc..0000000
--- a/src/main/java/it/cavallium/dbengine/client/BadBlock.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package it.cavallium.dbengine.client;
-
-import it.cavallium.buffer.Buf;
-import it.cavallium.dbengine.rpc.current.data.Column;
-import org.jetbrains.annotations.Nullable;
-
-public record BadBlock(String databaseName, @Nullable Column column, @Nullable Buf rawKey,
- @Nullable Throwable ex) {}
diff --git a/src/main/java/it/cavallium/dbengine/client/CompositeDatabase.java b/src/main/java/it/cavallium/dbengine/client/CompositeDatabase.java
index 8d51878..30afe41 100644
--- a/src/main/java/it/cavallium/dbengine/client/CompositeDatabase.java
+++ b/src/main/java/it/cavallium/dbengine/client/CompositeDatabase.java
@@ -26,7 +26,7 @@ public interface CompositeDatabase extends DatabaseProperties, DatabaseOperation
/**
* Find corrupted items
*/
- Stream badBlocks();
+ Stream verify();
void verifyChecksum();
}
diff --git a/src/main/java/it/cavallium/dbengine/client/DefaultDatabaseOptions.java b/src/main/java/it/cavallium/dbengine/client/DefaultDatabaseOptions.java
index 9dbec59..18567fe 100644
--- a/src/main/java/it/cavallium/dbengine/client/DefaultDatabaseOptions.java
+++ b/src/main/java/it/cavallium/dbengine/client/DefaultDatabaseOptions.java
@@ -66,6 +66,8 @@ public class DefaultDatabaseOptions {
DEFAULT_DEFAULT_COLUMN_OPTIONS,
List.of(),
NullableString.empty(),
+ NullableString.empty(),
+ false,
NullableString.empty()
);
diff --git a/src/main/java/it/cavallium/dbengine/client/VerificationProgress.java b/src/main/java/it/cavallium/dbengine/client/VerificationProgress.java
new file mode 100644
index 0000000..22f2da8
--- /dev/null
+++ b/src/main/java/it/cavallium/dbengine/client/VerificationProgress.java
@@ -0,0 +1,29 @@
+package it.cavallium.dbengine.client;
+
+import it.cavallium.buffer.Buf;
+import it.cavallium.dbengine.rpc.current.data.Column;
+import org.jetbrains.annotations.Nullable;
+
+public sealed interface VerificationProgress {
+ record BlockBad(String databaseName, Column column, Buf rawKey, String file, Throwable ex)
+ implements VerificationProgress {}
+ record FileOk(String databaseName, Column column, String file)
+ implements VerificationProgress {}
+ record Progress(String databaseName, Column column, String file,
+ long scanned, long total,
+ long fileScanned, long fileTotal)
+ implements VerificationProgress {
+
+ public double getProgress() {
+ return scanned / (double) total;
+ }
+
+ public double getFileProgress() {
+ return fileScanned / (double) fileTotal;
+ }
+ }
+
+ @Nullable String databaseName();
+ @Nullable Column column();
+ @Nullable String file();
+}
diff --git a/src/main/java/it/cavallium/dbengine/database/LLDictionary.java b/src/main/java/it/cavallium/dbengine/database/LLDictionary.java
index f9909dc..ad2c6d1 100644
--- a/src/main/java/it/cavallium/dbengine/database/LLDictionary.java
+++ b/src/main/java/it/cavallium/dbengine/database/LLDictionary.java
@@ -1,16 +1,14 @@
package it.cavallium.dbengine.database;
import it.cavallium.buffer.Buf;
-import it.cavallium.dbengine.client.BadBlock;
+import it.cavallium.dbengine.client.VerificationProgress;
import it.cavallium.dbengine.database.serialization.KVSerializationFunction;
import it.cavallium.dbengine.database.serialization.SerializationFunction;
-import java.io.IOException;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Stream;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import org.rocksdb.RocksDBException;
@SuppressWarnings("unused")
public interface LLDictionary extends LLKeyValueDatabaseStructure {
@@ -66,7 +64,7 @@ public interface LLDictionary extends LLKeyValueDatabaseStructure {
int prefixLength,
boolean smallRange);
- Stream badBlocks(LLRange range);
+ Stream badBlocks(LLRange range);
void setRange(LLRange range, Stream entries, boolean smallRange);
diff --git a/src/main/java/it/cavallium/dbengine/database/LLRange.java b/src/main/java/it/cavallium/dbengine/database/LLRange.java
index 7d7306d..defb906 100644
--- a/src/main/java/it/cavallium/dbengine/database/LLRange.java
+++ b/src/main/java/it/cavallium/dbengine/database/LLRange.java
@@ -1,6 +1,8 @@
package it.cavallium.dbengine.database;
import it.cavallium.buffer.Buf;
+import it.cavallium.dbengine.database.disk.LiveFileMetadata;
+import java.util.Objects;
import java.util.StringJoiner;
import org.jetbrains.annotations.Nullable;
@@ -19,6 +21,8 @@ public class LLRange {
private LLRange(@Nullable Buf min, @Nullable Buf max, @Nullable Buf single) {
assert single == null || (min == null && max == null);
+ assert min == null || max == null || min.compareTo(max) <= 0
+ : "Minimum buffer is bigger than maximum buffer: " + min + " > " + max;
this.min = min;
this.max = max;
this.single = single;
@@ -44,6 +48,57 @@ public class LLRange {
return new LLRange(min, max, null);
}
+ public static boolean isInside(LLRange rangeSub, LLRange rangeParent) {
+ if (rangeParent.isAll()) {
+ return true;
+ } else if (rangeParent.isSingle()) {
+ return Objects.equals(rangeSub, rangeParent);
+ } else {
+ return ((!rangeParent.hasMin() || (rangeSub.hasMin() && rangeParent.getMin().compareTo(rangeSub.getMin()) <= 0)))
+ && ((!rangeParent.hasMax() || (rangeSub.hasMax() && rangeParent.getMax().compareTo(rangeSub.getMax()) >= 0)));
+ }
+ }
+
+ @Nullable
+ public static LLRange intersect(LLRange rangeA, LLRange rangeB) {
+ boolean aEndInclusive = rangeA.isSingle();
+ boolean bEndInclusive = rangeB.isSingle();
+ Buf min = rangeA.isAll()
+ ? rangeB.getMin()
+ : (rangeB.isAll()
+ ? rangeA.getMin()
+ : (rangeA.getMin().compareTo(rangeB.getMin()) <= 0 ? rangeB.getMin() : rangeA.getMin()));
+ int aComparedToB;
+ Buf max;
+ boolean maxInclusive;
+ if (rangeA.isAll()) {
+ max = rangeB.getMax();
+ maxInclusive = bEndInclusive;
+ } else if (rangeB.isAll()) {
+ max = rangeA.getMax();
+ maxInclusive = aEndInclusive;
+ } else if ((aComparedToB = rangeA.getMax().compareTo(rangeB.getMax())) >= 0) {
+ max = rangeB.getMax();
+ if (aComparedToB == 0) {
+ maxInclusive = bEndInclusive && aEndInclusive;
+ } else {
+ maxInclusive = bEndInclusive;
+ }
+ } else {
+ max = rangeA.getMax();
+ maxInclusive = aEndInclusive;
+ }
+ if (min != null && max != null && min.compareTo(max) >= (maxInclusive ? 1 : 0)) {
+ return null;
+ } else {
+ if (min != null && min.equals(max)) {
+ return LLRange.single(min);
+ } else {
+ return LLRange.of(min, max);
+ }
+ }
+ }
+
public boolean isAll() {
return min == null && max == null && single == null;
}
@@ -108,12 +163,20 @@ public class LLRange {
return result;
}
+ @SuppressWarnings("UnnecessaryUnicodeEscape")
@Override
public String toString() {
- return new StringJoiner(", ", LLRange.class.getSimpleName() + "[", "]")
- .add("min=" + LLUtils.toString(min))
- .add("max=" + LLUtils.toString(max))
- .toString();
+ if (single != null) {
+ return "[" + single + "]";
+ } else if (min != null && max != null) {
+ return "[" + LLUtils.toString(min) + "," + LLUtils.toString(max) + ")";
+ } else if (min != null) {
+ return "[" + min + ",\u221E)";
+ } else if (max != null) {
+ return "[\u2205," + max + ")";
+ } else {
+ return "[\u221E)";
+ }
}
public LLRange copy() {
diff --git a/src/main/java/it/cavallium/dbengine/database/LLUtils.java b/src/main/java/it/cavallium/dbengine/database/LLUtils.java
index 3d25966..b6f9fa9 100644
--- a/src/main/java/it/cavallium/dbengine/database/LLUtils.java
+++ b/src/main/java/it/cavallium/dbengine/database/LLUtils.java
@@ -91,7 +91,7 @@ public class LLUtils {
private static final Consumer