This is an automated email from the ASF dual-hosted git repository.

broustant pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr-sandbox.git


The following commit(s) were added to refs/heads/main by this push:
     new 4e1819f  Support concurrency when reading transaction log encryption 
header. (#112)
4e1819f is described below

commit 4e1819ff8a3758becca19bf337ecd1b352dba805
Author: Bruno Roustant <[email protected]>
AuthorDate: Fri Nov 22 15:12:06 2024 +0100

    Support concurrency when reading transaction log encryption header. (#112)
---
 .../solr/encryption/EncryptionTransactionLog.java  | 36 ++++++++++++----------
 .../solr/encryption/EncryptionUpdateLog.java       |  9 ++----
 2 files changed, 21 insertions(+), 24 deletions(-)

diff --git 
a/encryption/src/main/java/org/apache/solr/encryption/EncryptionTransactionLog.java
 
b/encryption/src/main/java/org/apache/solr/encryption/EncryptionTransactionLog.java
index 13f08cf..1da3aa3 100644
--- 
a/encryption/src/main/java/org/apache/solr/encryption/EncryptionTransactionLog.java
+++ 
b/encryption/src/main/java/org/apache/solr/encryption/EncryptionTransactionLog.java
@@ -26,7 +26,6 @@ import java.io.IOException;
 import java.io.OutputStream;
 import java.nio.ByteBuffer;
 import java.nio.channels.FileChannel;
-import java.nio.channels.ReadableByteChannel;
 import java.nio.file.Path;
 import java.util.Collection;
 
@@ -140,28 +139,33 @@ public class EncryptionTransactionLog extends 
TransactionLog {
    *
    * @return The key reference number as a string; or null if the log is not 
encrypted.
    */
-  static String readEncryptionHeader(FileChannel channel, ByteBuffer 
readBuffer) throws IOException {
-    long position = channel.position();
-    if (position != 0) {
-      channel.position(0);
-    }
-    int magic = readBEInt(channel, readBuffer);
+  static String readEncryptionHeader(FileChannel channel) throws IOException {
+    int magic = readBEInt(channel, 0L, false);
     String keyRef = null;
     if (magic == ENCRYPTION_MAGIC) {
       // This file is encrypted.
       // Read the key reference that follows.
-      keyRef = Integer.toString(readBEInt(channel, readBuffer));
+      keyRef = Integer.toString(readBEInt(channel, 4L, true));
     }
-    channel.position(position);
     return keyRef;
   }
 
-  private static int readBEInt(ReadableByteChannel channel, ByteBuffer 
readBuffer) throws IOException {
-    readBuffer.clear();
-    int n = channel.read(readBuffer);
-    if (n != 4) {
-      throw new EOFException();
+  private static int readBEInt(FileChannel channel, long position, boolean 
requireAllBytes) throws IOException {
+    ByteBuffer readBuffer = ByteBuffer.allocate(4);
+    // Read 4 bytes.
+    int bytesRead = channel.read(readBuffer, position);
+    if (bytesRead < 4) {
+      if (requireAllBytes) {
+        throw new EOFException(
+            bytesRead == -1 || bytesRead == 0
+                ? "Header is empty; no data read."
+                : "Incomplete header; expected 4 bytes, but only read " + 
bytesRead + " bytes.");
+      } else {
+        // If not requiring all bytes, just return 0.
+        return 0;
+      }
     }
+    // Convert the 4 bytes to an integer in big-endian order
     return ((readBuffer.get(0) & 0xFF) << 24)
       | ((readBuffer.get(1) & 0xFF) << 16)
       | ((readBuffer.get(2) & 0xFF) << 8)
@@ -234,20 +238,18 @@ public class EncryptionTransactionLog extends 
TransactionLog {
 
     protected final EncryptionDirectorySupplier directorySupplier;
     protected final IvHolder ivHolder;
-    protected final ByteBuffer readBuffer;
 
     protected EncryptionChannelInputStreamOpener(
       EncryptionDirectorySupplier directorySupplier, IvHolder ivHolder) {
       this.directorySupplier = directorySupplier;
       this.ivHolder = ivHolder;
-      readBuffer = ByteBuffer.allocate(4);
     }
 
     @Override
     public ChannelFastInputStream open(FileChannel channel, long position) 
throws IOException {
       EncryptionDirectory directory = directorySupplier.get();
       try {
-        String keyRef = readEncryptionHeader(channel, readBuffer);
+        String keyRef = readEncryptionHeader(channel);
         if (keyRef != null) {
           // The IndexInput has to be wrapped to be decrypted with the key.
           DecryptingChannelInputStream dcis =
diff --git 
a/encryption/src/main/java/org/apache/solr/encryption/EncryptionUpdateLog.java 
b/encryption/src/main/java/org/apache/solr/encryption/EncryptionUpdateLog.java
index 237a499..db3a706 100644
--- 
a/encryption/src/main/java/org/apache/solr/encryption/EncryptionUpdateLog.java
+++ 
b/encryption/src/main/java/org/apache/solr/encryption/EncryptionUpdateLog.java
@@ -29,15 +29,11 @@ import org.apache.solr.update.UpdateLog;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.lang.invoke.MethodHandles;
-import java.nio.ByteBuffer;
 import java.nio.channels.FileChannel;
-import java.nio.file.CopyOption;
 import java.nio.file.Files;
-import java.nio.file.OpenOption;
 import java.nio.file.Path;
 import java.nio.file.StandardCopyOption;
 import java.nio.file.StandardOpenOption;
@@ -140,10 +136,9 @@ public class EncryptionUpdateLog extends UpdateLog {
           throws IOException {
     List<TransactionLog> allLogs = getAllLogs();
     if (!allLogs.isEmpty()) {
-      ByteBuffer readBuffer = ByteBuffer.allocate(4);
       for (TransactionLog log : allLogs) {
         try (FileChannel logChannel = 
FileChannel.open(((EncryptionTransactionLog) log).path(), 
StandardOpenOption.READ)) {
-          String logKeyRef = readEncryptionHeader(logChannel, readBuffer);
+          String logKeyRef = readEncryptionHeader(logChannel);
           String logKeyId = logKeyRef == null ? null : 
getKeyIdFromCommit(logKeyRef, commitUserData);
           if (!Objects.equals(logKeyId, keyId)) {
             return false;
@@ -178,7 +173,7 @@ public class EncryptionUpdateLog extends UpdateLog {
     assert log.refCount() <= 1;
     if (Files.size(log.path()) > 0) {
       try (FileChannel inputChannel = FileChannel.open(log.path(), 
StandardOpenOption.READ)) {
-        String inputKeyRef = readEncryptionHeader(inputChannel, 
ByteBuffer.allocate(4));
+        String inputKeyRef = readEncryptionHeader(inputChannel);
         if (!Objects.equals(inputKeyRef, activeKeyRef)) {
           Path newLogPath = log.path().resolveSibling(log.path().getFileName() 
+ ".enc");
           try (OutputStream outputStream = Files.newOutputStream(newLogPath, 
StandardOpenOption.CREATE)) {

Reply via email to