You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by yc...@apache.org on 2024/03/11 02:12:07 UTC
(cassandra-sidecar) branch trunk updated: CASSANDRASC-114 Make hash algorithm implementation pluggable
This is an automated email from the ASF dual-hosted git repository.
ycai pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra-sidecar.git
The following commit(s) were added to refs/heads/trunk by this push:
new ca1de4c CASSANDRASC-114 Make hash algorithm implementation pluggable
ca1de4c is described below
commit ca1de4cc2e594266c1fca9f83cfcac38d9a21c45
Author: Yifan Cai <yc...@apache.org>
AuthorDate: Fri Mar 8 12:17:38 2024 -0800
CASSANDRASC-114 Make hash algorithm implementation pluggable
patch by Yifan Cai; reviewed by Francisco Guerrero for CASSANDRASC-114
---
CHANGES.txt | 1 +
build.gradle | 4 +-
gradle.properties | 3 +-
.../apache/cassandra/sidecar/db/RestoreSlice.java | 7 +-
.../cassandra/sidecar/restore/RestoreJobUtil.java | 140 +++++++++++----------
.../sidecar/restore/RestoreProcessor.java | 9 +-
.../sidecar/restore/RestoreSliceTask.java | 7 +-
.../cassandra/sidecar/server/MainModule.java | 22 ++++
.../sidecar/utils/AsyncFileDigestVerifier.java | 30 ++++-
.../cassandra/sidecar/utils/DigestAlgorithm.java | 41 ++++++
.../sidecar/utils/DigestAlgorithmProvider.java | 39 ++++++
.../sidecar/utils/DigestVerifierFactory.java | 18 ++-
.../sidecar/utils/JdkMd5DigestProvider.java | 74 +++++++++++
.../cassandra/sidecar/utils/MD5DigestVerifier.java | 41 ++----
.../sidecar/utils/XXHash32DigestVerifier.java | 46 ++-----
.../cassandra/sidecar/utils/XXHash32Provider.java | 64 ++++++++++
.../sidecar/restore/RestoreJobUtilTest.java | 10 +-
.../sidecar/restore/RestoreProcessorTest.java | 2 +-
.../sidecar/restore/RestoreSliceTaskTest.java | 3 +-
.../sstableuploads/SSTableUploadHandlerTest.java | 11 +-
.../sidecar/utils/DigestVerifierFactoryTest.java | 14 ++-
.../sidecar/utils/MD5DigestVerifierTest.java | 2 +-
.../sidecar/utils/XXHash32DigestVerifierTest.java | 20 ++-
23 files changed, 431 insertions(+), 177 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index 351ca44..0fdc914 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,6 @@
1.0.0
-----
+ * Make hash algorithm implementation pluggable (CASSANDRASC-114)
* Fix ClosedChannelException when downloading from S3 (CASSANDRASC-112)
* Fix NPE thrown when getting StorageClient from pool (CASSANDRASC-110)
* Relocate Sidecar common classes in vertx-client-shaded (CASSANDRASC-104)
diff --git a/build.gradle b/build.gradle
index 5aa49d5..2db4461 100644
--- a/build.gradle
+++ b/build.gradle
@@ -197,7 +197,9 @@ dependencies {
implementation('ch.qos.logback:logback-core:1.2.3')
implementation('ch.qos.logback:logback-classic:1.2.3')
+
implementation(group: 'org.apache.commons', name: 'commons-lang3', version: '3.13.0')
+ implementation(group: 'commons-codec', name: 'commons-codec', version: "${project.commonsCodecVersion}")
// Jackson for yaml-based configuration parsing
implementation(group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: "${project.jacksonVersion}")
@@ -208,8 +210,6 @@ dependencies {
implementation('software.amazon.awssdk:s3')
implementation('software.amazon.awssdk:netty-nio-client')
- implementation(group: 'org.lz4', name: 'lz4-java', version: "${project.xxHashVersion}")
-
jolokia 'org.jolokia:jolokia-jvm:1.6.0:agent'
testImplementation "org.junit.jupiter:junit-jupiter-api:${project.junitVersion}"
diff --git a/gradle.properties b/gradle.properties
index 29f567c..98068d7 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -27,4 +27,5 @@ dtestApiVersion=0.0.16
dtestVersion=5.1
dtestDependencyName=cassandra-dtest-local-all
aswSdkVersion=2.20.43
-xxHashVersion=1.8.0
+# The dep is to introduce xxhash impl
+commonsCodecVersion=1.16.1
diff --git a/src/main/java/org/apache/cassandra/sidecar/db/RestoreSlice.java b/src/main/java/org/apache/cassandra/sidecar/db/RestoreSlice.java
index 6353894..7563e93 100644
--- a/src/main/java/org/apache/cassandra/sidecar/db/RestoreSlice.java
+++ b/src/main/java/org/apache/cassandra/sidecar/db/RestoreSlice.java
@@ -39,6 +39,7 @@ import org.apache.cassandra.sidecar.common.data.RestoreSliceStatus;
import org.apache.cassandra.sidecar.concurrent.ExecutorPools;
import org.apache.cassandra.sidecar.exceptions.RestoreJobExceptions;
import org.apache.cassandra.sidecar.exceptions.RestoreJobFatalException;
+import org.apache.cassandra.sidecar.restore.RestoreJobUtil;
import org.apache.cassandra.sidecar.restore.RestoreSliceTask;
import org.apache.cassandra.sidecar.restore.RestoreSliceTracker;
import org.apache.cassandra.sidecar.restore.StorageClient;
@@ -233,7 +234,8 @@ public class RestoreSlice
SSTableImporter importer,
double requiredUsableSpacePercentage,
RestoreSliceDatabaseAccessor sliceDatabaseAccessor,
- RestoreJobStats stats)
+ RestoreJobStats stats,
+ RestoreJobUtil restoreJobUtil)
{
if (isCancelled)
return promise -> promise.tryFail(RestoreJobExceptions.ofFatalSlice("Restore slice is cancelled",
@@ -246,7 +248,8 @@ public class RestoreSlice
executorPool, importer,
requiredUsableSpacePercentage,
sliceDatabaseAccessor,
- stats);
+ stats,
+ restoreJobUtil);
}
catch (IllegalStateException illegalState)
{
diff --git a/src/main/java/org/apache/cassandra/sidecar/restore/RestoreJobUtil.java b/src/main/java/org/apache/cassandra/sidecar/restore/RestoreJobUtil.java
index d33ff37..ef36316 100644
--- a/src/main/java/org/apache/cassandra/sidecar/restore/RestoreJobUtil.java
+++ b/src/main/java/org/apache/cassandra/sidecar/restore/RestoreJobUtil.java
@@ -19,8 +19,8 @@
package org.apache.cassandra.sidecar.restore;
import java.io.File;
-import java.io.FileInputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
@@ -34,23 +34,38 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.datastax.driver.core.utils.UUIDs;
-import net.jpountz.xxhash.StreamingXXHash32;
-import net.jpountz.xxhash.XXHashFactory;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.google.inject.name.Named;
import org.apache.cassandra.sidecar.exceptions.RestoreJobException;
import org.apache.cassandra.sidecar.exceptions.RestoreJobFatalException;
+import org.apache.cassandra.sidecar.utils.DigestAlgorithm;
+import org.apache.cassandra.sidecar.utils.DigestAlgorithmProvider;
/**
- * Utilities that only makes sense in the context of restore jobs. Avoid using it in the other scenarios.
+ * Utilities that only makes sense in the context of restore jobs.
+ *
+ * Note: Avoid using it in the other scenarios.
+ *
*/
+@Singleton
public class RestoreJobUtil
{
private static final Logger LOGGER = LoggerFactory.getLogger(RestoreJobUtil.class);
- private RestoreJobUtil() {}
private static final int KB_512 = 512 * 1024;
// it is part of upload id and get validated by
// org.apache.cassandra.sidecar.utils.SSTableUploadsPathBuilder.UPLOAD_ID_PATTERN
private static final String RESTORE_JOB_PREFIX = "c0ffee-";
private static final int RESTORE_JOB_PREFIX_LEN = RESTORE_JOB_PREFIX.length();
+ private static final int RESTORE_JOB_DEFAULT_HASH_SEED = 0;
+
+ private DigestAlgorithmProvider digestAlgorithmProvider;
+
+ @Inject
+ public RestoreJobUtil(@Named("xxhash32") DigestAlgorithmProvider digestAlgorithmProvider)
+ {
+ this.digestAlgorithmProvider = digestAlgorithmProvider;
+ }
/**
* Unzip a restore slice zip
@@ -84,65 +99,6 @@ public class RestoreJobUtil
}
}
- /**
- * Create a file that is protected from zip slip attack (https://security.snyk.io/research/zip-slip-vulnerability)
- * @param zipEntry zip entry to be extracted
- * @param targetDir directory to keep the unzipped files
- * @return a new file
- * @throws IOException failed to resolving path
- * @throws RestoreJobException if the zip file is malicious
- */
- private static File newProtectedTargetFile(ZipEntry zipEntry, File targetDir)
- throws IOException, RestoreJobException
- {
- File targetFile = new File(targetDir, zipEntry.getName());
-
- // Normalize the paths of both target dir and file
- String targetDirPath = targetDir.getCanonicalPath();
- String targetFilePath = targetFile.getCanonicalPath();
-
- if (!targetFilePath.startsWith(targetDirPath))
- {
- throw new RestoreJobException("Bad zip entry: " + zipEntry.getName());
- }
-
- return targetFile;
- }
-
- /**
- * @param file the file to use to perform the checksum
- * @return the checksum hex string of the file's content. XXHash32 is employed as the hash algorithm.
- */
- public static String checksum(File file) throws IOException
- {
- int seed = 0x9747b28c; // random seed for initializing
- return checksum(file, seed);
- }
-
- /**
- * @param file the file to use to perform the checksum
- * @param seed the seed to use for the hasher
- * @return the checksum hex string of the file's content. XXHash32 is employed as the hash algorithm.
- */
- public static String checksum(File file, int seed) throws IOException
- {
- try (FileInputStream fis = new FileInputStream(file))
- {
- // might have shared hashers with ThreadLocal
- XXHashFactory factory = XXHashFactory.safeInstance();
- try (StreamingXXHash32 hasher = factory.newStreamingHash32(seed))
- {
- byte[] buffer = new byte[KB_512];
- int len;
- while ((len = fis.read(buffer)) != -1)
- {
- hasher.update(buffer, 0, len);
- }
- return Long.toHexString(hasher.getValue());
- }
- }
- }
-
/**
* Resolve a prefixed job id for path
* @param jobId restore job id
@@ -211,4 +167,60 @@ public class RestoreJobUtil
});
}
}
+
+ /**
+ * Create a file that is protected from zip slip attack (https://security.snyk.io/research/zip-slip-vulnerability)
+ * @param zipEntry zip entry to be extracted
+ * @param targetDir directory to keep the unzipped files
+ * @return a new file
+ * @throws IOException failed to resolving path
+ * @throws RestoreJobException if the zip file is malicious
+ */
+ private static File newProtectedTargetFile(ZipEntry zipEntry, File targetDir)
+ throws IOException, RestoreJobException
+ {
+ File targetFile = new File(targetDir, zipEntry.getName());
+
+ // Normalize the paths of both target dir and file
+ String targetDirPath = targetDir.getCanonicalPath();
+ String targetFilePath = targetFile.getCanonicalPath();
+
+ if (!targetFilePath.startsWith(targetDirPath))
+ {
+ throw new RestoreJobException("Bad zip entry: " + zipEntry.getName());
+ }
+
+ return targetFile;
+ }
+
+ /**
+ * @param file the file to use to perform the checksum
+ * @return the checksum hex string of the file's content. XXHash32 is employed as the hash algorithm.
+ */
+ public String checksum(File file) throws IOException
+ {
+ return checksum(file, RESTORE_JOB_DEFAULT_HASH_SEED);
+ }
+
+ /**
+ * @param file the file to use to perform the checksum
+ * @param seed the seed to use for the hasher
+ * @return the checksum hex string of the file's content. XXHash32 is employed as the hash algorithm.
+ */
+ public String checksum(File file, int seed) throws IOException
+ {
+ try (InputStream fis = Files.newInputStream(file.toPath()))
+ {
+ try (DigestAlgorithm digestAlgorithm = digestAlgorithmProvider.get(seed))
+ {
+ byte[] buffer = new byte[KB_512];
+ int len;
+ while ((len = fis.read(buffer)) != -1)
+ {
+ digestAlgorithm.update(buffer, 0, len);
+ }
+ return digestAlgorithm.digest();
+ }
+ }
+ }
}
diff --git a/src/main/java/org/apache/cassandra/sidecar/restore/RestoreProcessor.java b/src/main/java/org/apache/cassandra/sidecar/restore/RestoreProcessor.java
index af6332f..1a438dc 100644
--- a/src/main/java/org/apache/cassandra/sidecar/restore/RestoreProcessor.java
+++ b/src/main/java/org/apache/cassandra/sidecar/restore/RestoreProcessor.java
@@ -61,6 +61,8 @@ public class RestoreProcessor implements PeriodicTask
private final double requiredUsableSpacePercentage; // value range: [0.0, 1.0)
private final RestoreSliceDatabaseAccessor sliceDatabaseAccessor;
private final RestoreJobStats stats;
+ private final RestoreJobUtil restoreJobUtil;
+
private volatile boolean isClosed = false; // OK to run close twice, so relax the control to volatile
@Inject
@@ -70,7 +72,8 @@ public class RestoreProcessor implements PeriodicTask
StorageClientPool s3ClientPool,
SSTableImporter importer,
RestoreSliceDatabaseAccessor sliceDatabaseAccessor,
- RestoreJobStats stats)
+ RestoreJobStats stats,
+ RestoreJobUtil restoreJobUtil)
{
this.pool = executorPools.internal();
this.s3ClientPool = s3ClientPool;
@@ -82,6 +85,7 @@ public class RestoreProcessor implements PeriodicTask
this.importer = importer;
this.sliceDatabaseAccessor = sliceDatabaseAccessor;
this.stats = stats;
+ this.restoreJobUtil = restoreJobUtil;
}
/**
@@ -131,7 +135,8 @@ public class RestoreProcessor implements PeriodicTask
sliceQueue.captureImportQueueLength();
pool.executeBlocking(slice.toAsyncTask(s3ClientPool, pool, importer,
requiredUsableSpacePercentage,
- sliceDatabaseAccessor, stats),
+ sliceDatabaseAccessor, stats,
+ restoreJobUtil),
false) // unordered
.onSuccess(restoreSlice -> {
if (slice.hasImported())
diff --git a/src/main/java/org/apache/cassandra/sidecar/restore/RestoreSliceTask.java b/src/main/java/org/apache/cassandra/sidecar/restore/RestoreSliceTask.java
index 0cec6f2..ecd0734 100644
--- a/src/main/java/org/apache/cassandra/sidecar/restore/RestoreSliceTask.java
+++ b/src/main/java/org/apache/cassandra/sidecar/restore/RestoreSliceTask.java
@@ -70,6 +70,7 @@ public class RestoreSliceTask implements Handler<Promise<RestoreSlice>>
private final double requiredUsableSpacePercentage;
private final RestoreSliceDatabaseAccessor sliceDatabaseAccessor;
private final RestoreJobStats stats;
+ private final RestoreJobUtil restoreJobUtil;
public RestoreSliceTask(RestoreSlice slice,
StorageClient s3Client,
@@ -77,7 +78,8 @@ public class RestoreSliceTask implements Handler<Promise<RestoreSlice>>
SSTableImporter importer,
double requiredUsableSpacePercentage,
RestoreSliceDatabaseAccessor sliceDatabaseAccessor,
- RestoreJobStats stats)
+ RestoreJobStats stats,
+ RestoreJobUtil restoreJobUtil)
{
Preconditions.checkArgument(!slice.job().isManagedBySidecar()
|| sliceDatabaseAccessor != null,
@@ -89,6 +91,7 @@ public class RestoreSliceTask implements Handler<Promise<RestoreSlice>>
this.requiredUsableSpacePercentage = requiredUsableSpacePercentage;
this.sliceDatabaseAccessor = sliceDatabaseAccessor;
this.stats = stats;
+ this.restoreJobUtil = restoreJobUtil;
}
@Override
@@ -442,7 +445,7 @@ public class RestoreSliceTask implements Handler<Promise<RestoreSlice>>
try
{
- String actualChecksum = RestoreJobUtil.checksum(file);
+ String actualChecksum = restoreJobUtil.checksum(file);
if (!actualChecksum.equals(expectedChecksum))
{
String msg = "Checksum does not match. Expected: " + expectedChecksum +
diff --git a/src/main/java/org/apache/cassandra/sidecar/server/MainModule.java b/src/main/java/org/apache/cassandra/sidecar/server/MainModule.java
index 008fadc..a85dbb6 100644
--- a/src/main/java/org/apache/cassandra/sidecar/server/MainModule.java
+++ b/src/main/java/org/apache/cassandra/sidecar/server/MainModule.java
@@ -98,7 +98,10 @@ import org.apache.cassandra.sidecar.stats.RestoreJobStats;
import org.apache.cassandra.sidecar.stats.SidecarSchemaStats;
import org.apache.cassandra.sidecar.stats.SidecarStats;
import org.apache.cassandra.sidecar.utils.CassandraVersionProvider;
+import org.apache.cassandra.sidecar.utils.DigestAlgorithmProvider;
+import org.apache.cassandra.sidecar.utils.JdkMd5DigestProvider;
import org.apache.cassandra.sidecar.utils.TimeProvider;
+import org.apache.cassandra.sidecar.utils.XXHash32Provider;
import static org.apache.cassandra.sidecar.common.utils.ByteUtils.bytesToHumanReadableBinaryPrefix;
import static org.apache.cassandra.sidecar.server.SidecarServerEvents.ON_SERVER_STOP;
@@ -507,6 +510,25 @@ public class MainModule extends AbstractModule
stats, sidecarInternalKeyspace, cqlSessionProvider);
}
+ /**
+ * The provided hasher is used in {@link org.apache.cassandra.sidecar.restore.RestoreJobUtil}
+ */
+ @Provides
+ @Singleton
+ @Named("xxhash32")
+ public DigestAlgorithmProvider xxHash32Provider()
+ {
+ return new XXHash32Provider();
+ }
+
+ @Provides
+ @Singleton
+ @Named("md5")
+ public DigestAlgorithmProvider md5Provider()
+ {
+ return new JdkMd5DigestProvider();
+ }
+
/**
* Builds the {@link InstanceMetadata} from the {@link InstanceConfiguration},
* a provided {@code versionProvider}, and {@code healthCheckFrequencyMillis}.
diff --git a/src/main/java/org/apache/cassandra/sidecar/utils/AsyncFileDigestVerifier.java b/src/main/java/org/apache/cassandra/sidecar/utils/AsyncFileDigestVerifier.java
index 790b54c..0174e12 100644
--- a/src/main/java/org/apache/cassandra/sidecar/utils/AsyncFileDigestVerifier.java
+++ b/src/main/java/org/apache/cassandra/sidecar/utils/AsyncFileDigestVerifier.java
@@ -18,6 +18,7 @@
package org.apache.cassandra.sidecar.utils;
+import java.io.IOException;
import java.util.Objects;
import org.slf4j.Logger;
@@ -46,11 +47,13 @@ public abstract class AsyncFileDigestVerifier<D extends Digest> implements Diges
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
protected final FileSystem fs;
protected final D digest;
+ private final DigestAlgorithm digestAlgorithm;
- protected AsyncFileDigestVerifier(FileSystem fs, D digest)
+ protected AsyncFileDigestVerifier(FileSystem fs, D digest, DigestAlgorithm digestAlgorithm)
{
this.fs = fs;
this.digest = Objects.requireNonNull(digest, "digest is required");
+ this.digestAlgorithm = digestAlgorithm;
}
/**
@@ -86,7 +89,30 @@ public abstract class AsyncFileDigestVerifier<D extends Digest> implements Diges
* @param asyncFile the async file to use for digest calculation
* @return a future with the computed digest for the provided {@link AsyncFile file}
*/
- protected abstract Future<String> calculateDigest(AsyncFile asyncFile);
+ protected Future<String> calculateDigest(AsyncFile asyncFile)
+ {
+ Promise<String> result = Promise.promise();
+
+ readFile(asyncFile, result,
+ buf -> {
+ byte[] bytes = buf.getBytes();
+ digestAlgorithm.update(bytes, 0, bytes.length);
+ },
+ onReadComplete -> {
+ result.complete(digestAlgorithm.digest());
+ try
+ {
+ digestAlgorithm.close();
+ }
+ catch (IOException e)
+ {
+ logger.warn("Potential memory leak due to failed to close hasher {}",
+ digestAlgorithm.getClass().getSimpleName());
+ }
+ });
+
+ return result.future();
+ }
protected void readFile(AsyncFile file, Promise<String> result, Handler<Buffer> onBufferAvailable,
Handler<Void> onReadComplete)
diff --git a/src/main/java/org/apache/cassandra/sidecar/utils/DigestAlgorithm.java b/src/main/java/org/apache/cassandra/sidecar/utils/DigestAlgorithm.java
new file mode 100644
index 0000000..415405c
--- /dev/null
+++ b/src/main/java/org/apache/cassandra/sidecar/utils/DigestAlgorithm.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.sidecar.utils;
+
+import java.io.Closeable;
+
+/**
+ * Abstraction for digest algorithms
+ */
+public interface DigestAlgorithm extends Closeable
+{
+ /**
+ * Updates the value of the digest with buf[off:off+len].
+ *
+ * @param buf the input data
+ * @param off the start offset in buf
+ * @param len the number of bytes to hash
+ */
+ void update(byte[] buf, int off, int len);
+
+ /**
+ * @return String value of the digest
+ */
+ String digest();
+}
diff --git a/src/main/java/org/apache/cassandra/sidecar/utils/DigestAlgorithmProvider.java b/src/main/java/org/apache/cassandra/sidecar/utils/DigestAlgorithmProvider.java
new file mode 100644
index 0000000..5a01355
--- /dev/null
+++ b/src/main/java/org/apache/cassandra/sidecar/utils/DigestAlgorithmProvider.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.sidecar.utils;
+
+/**
+ * Provides a digest algorithm implementation
+ */
+public interface DigestAlgorithmProvider
+{
+ /**
+ * @return a new digest algorithm instance with default seed 0
+ */
+ default DigestAlgorithm get()
+ {
+ return get(0);
+ }
+
+ /**
+ * @param seed seed for digest algorithm
+ * @return a new digest algorithm instance with the provided seed
+ */
+ DigestAlgorithm get(int seed);
+}
diff --git a/src/main/java/org/apache/cassandra/sidecar/utils/DigestVerifierFactory.java b/src/main/java/org/apache/cassandra/sidecar/utils/DigestVerifierFactory.java
index 3dd64a2..43734d7 100644
--- a/src/main/java/org/apache/cassandra/sidecar/utils/DigestVerifierFactory.java
+++ b/src/main/java/org/apache/cassandra/sidecar/utils/DigestVerifierFactory.java
@@ -20,6 +20,7 @@ package org.apache.cassandra.sidecar.utils;
import com.google.inject.Inject;
import com.google.inject.Singleton;
+import com.google.inject.name.Named;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.vertx.core.Future;
import io.vertx.core.MultiMap;
@@ -38,17 +39,24 @@ public class DigestVerifierFactory
@VisibleForTesting
static final DigestVerifier FALLBACK_VERIFIER = Future::succeededFuture;
private final FileSystem fs;
-
+ private final DigestAlgorithmProvider xxhash32;
+ private final DigestAlgorithmProvider md5;
/**
- * Constructs a new factory
+ * Constructs a new factory with a list of hash algorithms it supports
*
* @param vertx the vertx instance
+ * @param xxhash32 xxhash32 hash algorithm it supports
+ * @param md5 md5 hash algorithm it supports
*/
@Inject
- public DigestVerifierFactory(Vertx vertx)
+ public DigestVerifierFactory(Vertx vertx,
+ @Named("xxhash32") DigestAlgorithmProvider xxhash32,
+ @Named("md5") DigestAlgorithmProvider md5)
{
this.fs = vertx.fileSystem();
+ this.xxhash32 = xxhash32;
+ this.md5 = md5;
}
/***
@@ -64,11 +72,11 @@ public class DigestVerifierFactory
{
if (headers.contains(CONTENT_XXHASH32))
{
- return XXHash32DigestVerifier.create(fs, headers);
+ return XXHash32DigestVerifier.create(fs, headers, xxhash32);
}
else if (headers.contains(HttpHeaderNames.CONTENT_MD5.toString()))
{
- return MD5DigestVerifier.create(fs, headers);
+ return MD5DigestVerifier.create(fs, headers, md5);
}
// Fallback to no-op validator
return FALLBACK_VERIFIER;
diff --git a/src/main/java/org/apache/cassandra/sidecar/utils/JdkMd5DigestProvider.java b/src/main/java/org/apache/cassandra/sidecar/utils/JdkMd5DigestProvider.java
new file mode 100644
index 0000000..6f213cb
--- /dev/null
+++ b/src/main/java/org/apache/cassandra/sidecar/utils/JdkMd5DigestProvider.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.sidecar.utils;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Base64;
+
+/**
+ * Provides the MD5 implementation from JDK
+ */
+public class JdkMd5DigestProvider implements DigestAlgorithmProvider
+{
+ @Override
+ public DigestAlgorithm get(int seed)
+ {
+ return new JdkMD5Digest();
+ }
+
+ /**
+ * MD5 implementation from JDK
+ */
+ public static class JdkMD5Digest implements DigestAlgorithm
+ {
+ private final MessageDigest md5;
+
+ public JdkMD5Digest()
+ {
+ try
+ {
+ this.md5 = MessageDigest.getInstance("MD5");
+ }
+ catch (NoSuchAlgorithmException ex)
+ {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ @Override
+ public void update(byte[] buf, int off, int len)
+ {
+ md5.update(buf, off, len);
+ }
+
+ @Override
+ public String digest()
+ {
+ return Base64.getEncoder().encodeToString(md5.digest());
+ }
+
+ @Override
+ public void close()
+ {
+ // MessageDigest does not require to be closed
+ }
+ }
+
+}
diff --git a/src/main/java/org/apache/cassandra/sidecar/utils/MD5DigestVerifier.java b/src/main/java/org/apache/cassandra/sidecar/utils/MD5DigestVerifier.java
index ed4218d..7b80b8c 100644
--- a/src/main/java/org/apache/cassandra/sidecar/utils/MD5DigestVerifier.java
+++ b/src/main/java/org/apache/cassandra/sidecar/utils/MD5DigestVerifier.java
@@ -18,18 +18,11 @@
package org.apache.cassandra.sidecar.utils;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.Base64;
-
import io.netty.handler.codec.http.HttpHeaderNames;
-import io.vertx.core.Future;
import io.vertx.core.MultiMap;
-import io.vertx.core.Promise;
-import io.vertx.core.file.AsyncFile;
import io.vertx.core.file.FileSystem;
import org.apache.cassandra.sidecar.common.data.MD5Digest;
-import org.jetbrains.annotations.VisibleForTesting;
+import org.jetbrains.annotations.NotNull;
/**
* Implementation of {@link DigestVerifier}. Here we use MD5 implementation of {@link java.security.MessageDigest}
@@ -37,36 +30,16 @@ import org.jetbrains.annotations.VisibleForTesting;
*/
public class MD5DigestVerifier extends AsyncFileDigestVerifier<MD5Digest>
{
- protected MD5DigestVerifier(FileSystem fs, MD5Digest digest)
+ protected MD5DigestVerifier(@NotNull FileSystem fs, @NotNull MD5Digest digest,
+ @NotNull DigestAlgorithm digestAlgorithm)
{
- super(fs, digest);
+ super(fs, digest, digestAlgorithm);
}
- public static DigestVerifier create(FileSystem fs, MultiMap headers)
+ public static DigestVerifier create(FileSystem fs, MultiMap headers,
+ DigestAlgorithmProvider digestAlgorithmProvider)
{
MD5Digest md5Digest = new MD5Digest(headers.get(HttpHeaderNames.CONTENT_MD5.toString()));
- return new MD5DigestVerifier(fs, md5Digest);
- }
-
- @Override
- @VisibleForTesting
- protected Future<String> calculateDigest(AsyncFile file)
- {
- MessageDigest digest;
- try
- {
- digest = MessageDigest.getInstance("MD5");
- }
- catch (NoSuchAlgorithmException e)
- {
- return Future.failedFuture(e);
- }
-
- Promise<String> result = Promise.promise();
-
- readFile(file, result, buf -> digest.update(buf.getBytes()),
- _v -> result.complete(Base64.getEncoder().encodeToString(digest.digest())));
-
- return result.future();
+ return new MD5DigestVerifier(fs, md5Digest, digestAlgorithmProvider.get());
}
}
diff --git a/src/main/java/org/apache/cassandra/sidecar/utils/XXHash32DigestVerifier.java b/src/main/java/org/apache/cassandra/sidecar/utils/XXHash32DigestVerifier.java
index b1944c6..14347ce 100644
--- a/src/main/java/org/apache/cassandra/sidecar/utils/XXHash32DigestVerifier.java
+++ b/src/main/java/org/apache/cassandra/sidecar/utils/XXHash32DigestVerifier.java
@@ -18,15 +18,10 @@
package org.apache.cassandra.sidecar.utils;
-import io.vertx.core.Future;
import io.vertx.core.MultiMap;
-import io.vertx.core.Promise;
-import io.vertx.core.file.AsyncFile;
import io.vertx.core.file.FileSystem;
-import net.jpountz.xxhash.StreamingXXHash32;
-import net.jpountz.xxhash.XXHashFactory;
import org.apache.cassandra.sidecar.common.data.XXHash32Digest;
-import org.jetbrains.annotations.VisibleForTesting;
+import org.jetbrains.annotations.NotNull;
import static org.apache.cassandra.sidecar.common.http.SidecarHttpHeaderNames.CONTENT_XXHASH32;
import static org.apache.cassandra.sidecar.common.http.SidecarHttpHeaderNames.CONTENT_XXHASH32_SEED;
@@ -37,48 +32,27 @@ import static org.apache.cassandra.sidecar.common.http.SidecarHttpHeaderNames.CO
*/
public class XXHash32DigestVerifier extends AsyncFileDigestVerifier<XXHash32Digest>
{
- protected XXHash32DigestVerifier(FileSystem fs, XXHash32Digest digest)
+ protected XXHash32DigestVerifier(@NotNull FileSystem fs, @NotNull XXHash32Digest digest,
+ @NotNull DigestAlgorithm digestAlgorithm)
{
- super(fs, digest);
+ super(fs, digest, digestAlgorithm);
}
- public static XXHash32DigestVerifier create(FileSystem fs, MultiMap headers)
+ public static XXHash32DigestVerifier create(FileSystem fs, MultiMap headers,
+ DigestAlgorithmProvider digestAlgorithmProvider)
{
XXHash32Digest digest = new XXHash32Digest(headers.get(CONTENT_XXHASH32), headers.get(CONTENT_XXHASH32_SEED));
- return new XXHash32DigestVerifier(fs, digest);
+ DigestAlgorithm digestAlgorithm = digestAlgorithmProvider.get(maybeGetSeedOrDefault(digest));
+ return new XXHash32DigestVerifier(fs, digest, digestAlgorithm);
}
- @Override
- @VisibleForTesting
- protected Future<String> calculateDigest(AsyncFile file)
- {
- Promise<String> result = Promise.promise();
- Future<String> future = result.future();
-
- // might have shared hashers with ThreadLocal
- XXHashFactory factory = XXHashFactory.safeInstance();
-
- int seed = maybeGetSeedOrDefault();
- StreamingXXHash32 hasher = factory.newStreamingHash32(seed);
-
- future.onComplete(ignored -> hasher.close());
-
- readFile(file, result, buf -> {
- byte[] bytes = buf.getBytes();
- hasher.update(bytes, 0, bytes.length);
- },
- _v -> result.complete(Long.toHexString(hasher.getValue())));
-
- return future;
- }
-
- protected int maybeGetSeedOrDefault()
+ protected static int maybeGetSeedOrDefault(XXHash32Digest digest)
{
String seedHex = digest.seedHex();
if (seedHex != null)
{
return (int) Long.parseLong(seedHex, 16);
}
- return 0x9747b28c; // random seed for initializing
+ return 0;
}
}
diff --git a/src/main/java/org/apache/cassandra/sidecar/utils/XXHash32Provider.java b/src/main/java/org/apache/cassandra/sidecar/utils/XXHash32Provider.java
new file mode 100644
index 0000000..7c45e9f
--- /dev/null
+++ b/src/main/java/org/apache/cassandra/sidecar/utils/XXHash32Provider.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.sidecar.utils;
+
+import org.apache.commons.codec.digest.XXHash32;
+
+/**
+ * Provides the XXHash32 implementation from commons-codec
+ */
+public class XXHash32Provider implements DigestAlgorithmProvider
+{
+ @Override
+ public DigestAlgorithm get(int seed)
+ {
+ return new Lz4XXHash32(seed);
+ }
+
+ /**
+ * XXHash32 implementation from LZ4
+ */
+ public static class Lz4XXHash32 implements DigestAlgorithm
+ {
+ private final XXHash32 xxHash32;
+
+ Lz4XXHash32(int seed)
+ {
+ this.xxHash32 = new XXHash32(seed);
+ }
+
+ @Override
+ public void update(byte[] buf, int off, int len)
+ {
+ xxHash32.update(buf, off, len);
+ }
+
+ @Override
+ public String digest()
+ {
+ return Long.toHexString(xxHash32.getValue());
+ }
+
+ @Override
+ public void close()
+ {
+ // XXHash32 does not require to be closed
+ }
+ }
+}
diff --git a/src/test/java/org/apache/cassandra/sidecar/restore/RestoreJobUtilTest.java b/src/test/java/org/apache/cassandra/sidecar/restore/RestoreJobUtilTest.java
index 01af3d9..8c950cc 100644
--- a/src/test/java/org/apache/cassandra/sidecar/restore/RestoreJobUtilTest.java
+++ b/src/test/java/org/apache/cassandra/sidecar/restore/RestoreJobUtilTest.java
@@ -29,6 +29,7 @@ import org.junit.jupiter.api.io.TempDir;
import com.datastax.driver.core.utils.UUIDs;
import org.apache.cassandra.sidecar.exceptions.RestoreJobFatalException;
+import org.apache.cassandra.sidecar.utils.XXHash32Provider;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
@@ -43,11 +44,12 @@ class RestoreJobUtilTest
{
File file = new File(testDirRoot, "checksum.txt");
Files.write(file.toPath(), "XXHash32 is employed as the hash algorithm".getBytes(StandardCharsets.UTF_8));
- String checksum = RestoreJobUtil.checksum(file);
+ RestoreJobUtil util = new RestoreJobUtil(new XXHash32Provider());
+ String checksum = util.checksum(file);
assertThat(checksum)
- .describedAs("Hasher should return 32 bits checksum == 8 characters")
- .hasSize(16)
- .isEqualTo("ffffffffa89219eb"); // hash of "XXHash32 is employed as the hash algorithm"
+ .describedAs("Hasher should return 32 bits checksum == 4 characters")
+ .hasSize(8)
+ .isEqualTo("a0051d07"); // hash of "XXHash32 is employed as the hash algorithm"
}
@Test
diff --git a/src/test/java/org/apache/cassandra/sidecar/restore/RestoreProcessorTest.java b/src/test/java/org/apache/cassandra/sidecar/restore/RestoreProcessorTest.java
index 83ddc70..c3fafc8 100644
--- a/src/test/java/org/apache/cassandra/sidecar/restore/RestoreProcessorTest.java
+++ b/src/test/java/org/apache/cassandra/sidecar/restore/RestoreProcessorTest.java
@@ -175,7 +175,7 @@ class RestoreProcessorTest
RestoreSlice slice = mock(RestoreSlice.class, Mockito.RETURNS_DEEP_STUBS);
when(slice.jobId()).thenReturn(UUIDs.timeBased());
when(slice.owner().id()).thenReturn(1);
- when(slice.toAsyncTask(any(), any(), any(), anyDouble(), any(), any())).thenReturn(promise -> {
+ when(slice.toAsyncTask(any(), any(), any(), anyDouble(), any(), any(), any())).thenReturn(promise -> {
Uninterruptibles.awaitUninterruptibly(latch);
promise.complete(slice);
});
diff --git a/src/test/java/org/apache/cassandra/sidecar/restore/RestoreSliceTaskTest.java b/src/test/java/org/apache/cassandra/sidecar/restore/RestoreSliceTaskTest.java
index 80f4f19..728f5d2 100644
--- a/src/test/java/org/apache/cassandra/sidecar/restore/RestoreSliceTaskTest.java
+++ b/src/test/java/org/apache/cassandra/sidecar/restore/RestoreSliceTaskTest.java
@@ -262,7 +262,8 @@ class RestoreSliceTaskTest
SSTableImporter importer, double requiredUsableSpacePercentage,
RestoreSliceDatabaseAccessor sliceDatabaseAccessor, RestoreJobStats stats)
{
- super(slice, s3Client, executorPool, importer, requiredUsableSpacePercentage, sliceDatabaseAccessor, stats);
+ super(slice, s3Client, executorPool, importer, requiredUsableSpacePercentage, sliceDatabaseAccessor, stats,
+ null);
this.slice = slice;
this.stats = stats;
}
diff --git a/src/test/java/org/apache/cassandra/sidecar/routes/sstableuploads/SSTableUploadHandlerTest.java b/src/test/java/org/apache/cassandra/sidecar/routes/sstableuploads/SSTableUploadHandlerTest.java
index 2694fb4..caf76e6 100644
--- a/src/test/java/org/apache/cassandra/sidecar/routes/sstableuploads/SSTableUploadHandlerTest.java
+++ b/src/test/java/org/apache/cassandra/sidecar/routes/sstableuploads/SSTableUploadHandlerTest.java
@@ -97,7 +97,7 @@ class SSTableUploadHandlerTest extends BaseUploadsHandlerTest
{
UUID uploadId = UUID.randomUUID();
sendUploadRequestAndVerify(context, uploadId, "ks", "tbl", "with-correct-xxhash.db",
- new XXHash32Digest("7a28edc0"),
+ new XXHash32Digest("21228a35"),
Files.size(Paths.get(FILE_TO_BE_UPLOADED)),
HttpResponseStatus.OK.code(),
false);
@@ -108,7 +108,7 @@ class SSTableUploadHandlerTest extends BaseUploadsHandlerTest
{
UUID uploadId = UUID.randomUUID();
sendUploadRequestAndVerify(context, uploadId, "ks", "tbl", "with-correct-xxhash.db",
- new XXHash32Digest("ffffffffb9510d6b", "55555555"),
+ new XXHash32Digest("b9510d6b", "55555555"),
Files.size(Paths.get(FILE_TO_BE_UPLOADED)),
HttpResponseStatus.OK.code(),
false);
@@ -409,7 +409,12 @@ class SSTableUploadHandlerTest extends BaseUploadsHandlerTest
}
HttpResponse<Buffer> httpResponse = response.result();
- assertThat(httpResponse.statusCode()).isEqualTo(expectedRetCode);
+ if (httpResponse.statusCode() != expectedRetCode)
+ {
+ context.failNow("Status code mismatched. Expected: " + expectedRetCode +
+ "; actual: " + httpResponse.statusCode());
+ return;
+ }
if (responseValidator != null)
{
diff --git a/src/test/java/org/apache/cassandra/sidecar/utils/DigestVerifierFactoryTest.java b/src/test/java/org/apache/cassandra/sidecar/utils/DigestVerifierFactoryTest.java
index 810e015..f9460ce 100644
--- a/src/test/java/org/apache/cassandra/sidecar/utils/DigestVerifierFactoryTest.java
+++ b/src/test/java/org/apache/cassandra/sidecar/utils/DigestVerifierFactoryTest.java
@@ -43,11 +43,10 @@ class DigestVerifierFactoryTest
options = new HeadersMultiMap();
}
-
@Test
void testEmptyFactoryReturnsFallbackVerifier()
{
- DigestVerifier verifier = new DigestVerifierFactory(vertx).verifier(options);
+ DigestVerifier verifier = newFactory().verifier(options);
assertThat(verifier).as("should fallback to the fallback verifier when no verifiers are configured")
.isNotNull()
.isSameAs(FALLBACK_VERIFIER);
@@ -57,7 +56,7 @@ class DigestVerifierFactoryTest
void testMd5Verifier()
{
options.set("content-md5", "md5-header");
- DigestVerifier verifier = new DigestVerifierFactory(vertx).verifier(options);
+ DigestVerifier verifier = newFactory().verifier(options);
assertThat(verifier).as("MD5DigestVerifier can verify MD5 content headers")
.isNotNull()
@@ -68,7 +67,7 @@ class DigestVerifierFactoryTest
void testXXHashVerifier()
{
options.set(CONTENT_XXHASH32, "xxhash-header");
- DigestVerifier verifier = new DigestVerifierFactory(vertx).verifier(options);
+ DigestVerifier verifier = newFactory().verifier(options);
assertThat(verifier).as("XXHashDigestVerifier can verify XXHash content headers")
.isNotNull()
@@ -80,10 +79,15 @@ class DigestVerifierFactoryTest
{
options.set("content-md5", "md5-header")
.set(CONTENT_XXHASH32, "xxhash-header");
- DigestVerifier verifier = new DigestVerifierFactory(vertx).verifier(options);
+ DigestVerifier verifier = newFactory().verifier(options);
assertThat(verifier).as("XXHashDigestVerifier is selected when both headers are present")
.isNotNull()
.isInstanceOf(XXHash32DigestVerifier.class);
}
+
+ private DigestVerifierFactory newFactory()
+ {
+ return new DigestVerifierFactory(vertx, new XXHash32Provider(), new JdkMd5DigestProvider());
+ }
}
diff --git a/src/test/java/org/apache/cassandra/sidecar/utils/MD5DigestVerifierTest.java b/src/test/java/org/apache/cassandra/sidecar/utils/MD5DigestVerifierTest.java
index 550ef8e..0dce3e3 100644
--- a/src/test/java/org/apache/cassandra/sidecar/utils/MD5DigestVerifierTest.java
+++ b/src/test/java/org/apache/cassandra/sidecar/utils/MD5DigestVerifierTest.java
@@ -107,7 +107,7 @@ class MD5DigestVerifierTest
public ExposeAsyncFileMD5DigestVerifier(FileSystem fs, MD5Digest md5Digest)
{
- super(fs, md5Digest);
+ super(fs, md5Digest, new JdkMd5DigestProvider.JdkMD5Digest());
}
@Override
diff --git a/src/test/java/org/apache/cassandra/sidecar/utils/XXHash32DigestVerifierTest.java b/src/test/java/org/apache/cassandra/sidecar/utils/XXHash32DigestVerifierTest.java
index ff7566e..a5e0668 100644
--- a/src/test/java/org/apache/cassandra/sidecar/utils/XXHash32DigestVerifierTest.java
+++ b/src/test/java/org/apache/cassandra/sidecar/utils/XXHash32DigestVerifierTest.java
@@ -33,12 +33,11 @@ import io.vertx.core.file.AsyncFile;
import io.vertx.core.file.FileSystem;
import io.vertx.ext.web.handler.HttpException;
import org.apache.cassandra.sidecar.common.data.XXHash32Digest;
+import org.apache.cassandra.sidecar.restore.RestoreJobUtil;
import org.assertj.core.api.InstanceOfAssertFactories;
-import static org.apache.cassandra.sidecar.restore.RestoreJobUtil.checksum;
import static org.assertj.core.api.Assertions.as;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatNullPointerException;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.from;
@@ -52,32 +51,29 @@ class XXHash32DigestVerifierTest
@TempDir
static Path tempDir;
static Path randomFilePath;
+ static RestoreJobUtil restoreJobUtil;
@BeforeAll
static void setup() throws IOException
{
vertx = Vertx.vertx();
- randomFilePath = TestFileUtils.prepareTestFile(tempDir, "random-file.txt", 1024);
- }
+ restoreJobUtil = new RestoreJobUtil(new XXHash32Provider());
- @Test
- void failsWhenDigestIsNull()
- {
- assertThatNullPointerException().isThrownBy(() -> newVerifier(null)).withMessage("digest is required");
+ randomFilePath = TestFileUtils.prepareTestFile(tempDir, "random-file.txt", 1024);
}
@Test
void testFileDescriptorsClosedWithValidDigest() throws IOException, InterruptedException
{
- XXHash32Digest digest = new XXHash32Digest(checksum(randomFilePath.toFile()));
+ XXHash32Digest digest = new XXHash32Digest(restoreJobUtil.checksum(randomFilePath.toFile()));
runTestScenario(randomFilePath, digest, false);
}
@Test
void failsWithNonDefaultSeedAndSeedIsNotPassedAsAnOption() throws IOException, InterruptedException
{
- XXHash32Digest digest = new XXHash32Digest(checksum(randomFilePath.toFile(), 0x55555555));
+ XXHash32Digest digest = new XXHash32Digest(restoreJobUtil.checksum(randomFilePath.toFile(), 0x55555555));
runTestScenario(randomFilePath, digest, true);
}
@@ -85,7 +81,7 @@ class XXHash32DigestVerifierTest
void testWithCustomSeed() throws IOException, InterruptedException
{
int seed = 0x55555555;
- XXHash32Digest digest = new XXHash32Digest(checksum(randomFilePath.toFile(), seed), seed);
+ XXHash32Digest digest = new XXHash32Digest(restoreJobUtil.checksum(randomFilePath.toFile(), seed), seed);
runTestScenario(randomFilePath, digest, false);
}
@@ -142,7 +138,7 @@ class XXHash32DigestVerifierTest
public ExposeAsyncFileXXHash32DigestVerifier(FileSystem fs, XXHash32Digest digest)
{
- super(fs, digest);
+ super(fs, digest, new XXHash32Provider.Lz4XXHash32(maybeGetSeedOrDefault(digest)));
}
@Override
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cassandra.apache.org
For additional commands, e-mail: commits-help@cassandra.apache.org