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

elserj pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-ratis.git


The following commit(s) were added to refs/heads/master by this push:
     new 5f59dea  RATIS-546. Configurable value sizes on VerificationTool
5f59dea is described below

commit 5f59dea55fd6e3e85085781eeae4f793332d80de
Author: Josh Elser <[email protected]>
AuthorDate: Mon May 13 19:10:32 2019 -0400

    RATIS-546. Configurable value sizes on VerificationTool
---
 .../ratis/logservice/tool/VerificationTool.java    | 89 +++++++++++++++++++---
 .../logservice/tool/TestVerificationTool.java      | 59 ++++++++++++++
 2 files changed, 136 insertions(+), 12 deletions(-)

diff --git 
a/ratis-logservice/src/main/java/org/apache/ratis/logservice/tool/VerificationTool.java
 
b/ratis-logservice/src/main/java/org/apache/ratis/logservice/tool/VerificationTool.java
index cf8216d..1adbcdb 100644
--- 
a/ratis-logservice/src/main/java/org/apache/ratis/logservice/tool/VerificationTool.java
+++ 
b/ratis-logservice/src/main/java/org/apache/ratis/logservice/tool/VerificationTool.java
@@ -23,6 +23,7 @@ import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Random;
 import java.util.Set;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -51,14 +52,16 @@ public class VerificationTool {
     private int numLogs = 10;
     @Parameter(names = {"-nr", "--numRecords"}, description = "Number of 
records per log")
     private int numRecords = 1000;
-    @Parameter(names = {"-w", "--write"}, description = "Write to the logs")
+    @Parameter(names = {"-w", "--write"}, description = "Write to the logs", 
arity = 1)
     private boolean write = true;
-    @Parameter(names = {"-r", "--read"}, description = "Read the logs")
+    @Parameter(names = {"-r", "--read"}, description = "Read the logs", arity 
= 1)
     private boolean read = true;
     @Parameter(names = {"-l", "--logFrequency"}, description = "Print update 
every N operations")
     private int logFrequency = 50;
     @Parameter(names = {"-h", "--help"}, description = "Help", help = true)
     private boolean help = false;
+    @Parameter(names = {"-s", "--size"}, description = "Size in bytes of each 
value")
+    private int recordSize = -1;
 
     public static final String LOG_NAME_PREFIX = "testlog";
     public static final String MESSAGE_PREFIX = "message";
@@ -95,7 +98,7 @@ public class VerificationTool {
                 LOG.info("Deleting {}", logName);
                 client.deleteLog(logName);
               }
-              BulkWriter writer = new BulkWriter(getLogName(i), client, 
tool.numRecords, tool.logFrequency);
+              BulkWriter writer = new BulkWriter(getLogName(i), client, 
tool.numRecords, tool.logFrequency, tool.recordSize);
               futures.add(executor.submit(writer));
           }
           waitForCompletion(futures);
@@ -105,7 +108,7 @@ public class VerificationTool {
           LOG.info("Executing parallel reads");
           futures = new ArrayList<Future<?>>(tool.numLogs);
           for (int i = 0; i < tool.numLogs; i++) {
-              BulkReader reader = new BulkReader(getLogName(i), client, 
tool.numRecords, tool.logFrequency);
+              BulkReader reader = new BulkReader(getLogName(i), client, 
tool.numRecords, tool.logFrequency, tool.recordSize);
               futures.add(executor.submit(reader));
           }
           waitForCompletion(futures);
@@ -134,22 +137,85 @@ public class VerificationTool {
     }
 
     static abstract class Operation implements Runnable {
+      static final byte DIVIDER_BYTE = '_';
       final LogName logName;
       final LogServiceClient client;
       final int numRecords;
       final int logFreq;
+      final int valueSize;
 
-      Operation(LogName logName, LogServiceClient client, int numRecords, int 
logFreq) {
+      Operation(LogName logName, LogServiceClient client, int numRecords, int 
logFreq, int valueSize) {
         this.logName = logName;
         this.client = client;
         this.numRecords = numRecords;
         this.logFreq = logFreq;
+        this.valueSize = valueSize;
+      }
+
+      ByteBuffer createValue(String prefix) {
+        if (valueSize == -1) {
+          return ByteBuffer.wrap(prefix.getBytes(StandardCharsets.UTF_8));
+        }
+        byte[] value = new byte[valueSize];
+        byte[] prefixBytes = prefix.getBytes(StandardCharsets.UTF_8);
+        // Write as much of the prefix as possible
+        if (prefixBytes.length > valueSize) {
+          System.arraycopy(prefixBytes, 0, value, 0, valueSize);
+          return ByteBuffer.wrap(value);
+        }
+
+        // Write the full prefix
+        System.arraycopy(prefixBytes, 0, value, 0, prefixBytes.length);
+        int bytesWritten = prefixBytes.length;
+
+        // Write the divider (but only if we can write the whole thing)
+        if (bytesWritten + 1 > valueSize) {
+          return ByteBuffer.wrap(value);
+        }
+
+        value[bytesWritten] = DIVIDER_BYTE;
+        bytesWritten += 1;
+
+        // Generate random data to pad the value
+        int bytesToGenerate = valueSize - bytesWritten;
+        Random r = new Random();
+        byte[] suffix = new byte[bytesToGenerate];
+        r.nextBytes(suffix);
+        System.arraycopy(suffix, 0, value, bytesWritten, suffix.length);
+
+        return ByteBuffer.wrap(value);
+      }
+
+      String parseValue(ByteBuffer buff) {
+        if (!buff.hasArray()) {
+          throw new IllegalArgumentException("Require a ByteBuffer with a 
backing array");
+        }
+        if (valueSize == -1) {
+          return new String(buff.array(), buff.arrayOffset(), 
buff.remaining(), StandardCharsets.UTF_8);
+        }
+        int length = buff.limit() - buff.arrayOffset();
+        byte[] value = new byte[length];
+        System.arraycopy(buff.array(), buff.arrayOffset(), value, 0, length);
+
+        int dividerOffset = -1;
+        for (int i = 0; i < value.length; i++) {
+          if (value[i] == DIVIDER_BYTE) {
+            dividerOffset = i;
+            break;
+          }
+        }
+        // We didn't have enough space to write the divider, return all of the 
bytes
+        if (dividerOffset < 0) {
+          return new String(value, StandardCharsets.UTF_8);
+        }
+
+        return new String(value, 0, dividerOffset, StandardCharsets.UTF_8);
       }
     }
 
     static class BulkWriter extends Operation {
-        BulkWriter(LogName logName, LogServiceClient client, int numRecords, 
int logFreq) {
-            super(logName, client, numRecords, logFreq);
+        BulkWriter(LogName logName, LogServiceClient client, int numRecords, 
int logFreq, int valueSize) {
+            super(logName, client, numRecords, logFreq, valueSize);
         }
 
         public void run() {
@@ -162,7 +228,7 @@ public class VerificationTool {
                     if (i % logFreq == 0) {
                       LOG.info(logName + " Writing " + message);
                     }
-                    
writer.write(ByteBuffer.wrap(message.getBytes(StandardCharsets.UTF_8)));
+                    writer.write(createValue(message));
                 }
                 writer.close();
                 LOG.info("{} log entries written to log {} successfully.", 
numRecords, logName);
@@ -173,8 +239,8 @@ public class VerificationTool {
     }
 
     static class BulkReader extends Operation {
-        BulkReader(LogName logName, LogServiceClient client, int numRecords, 
int logFreq) {
-          super(logName, client, numRecords, logFreq);
+        BulkReader(LogName logName, LogServiceClient client, int numRecords, 
int logFreq, int valueSize) {
+          super(logName, client, numRecords, logFreq, valueSize);
       }
 
         public void run() {
@@ -189,8 +255,7 @@ public class VerificationTool {
                 }
                 for (int i = 0; i < size; i++) {
                     ByteBuffer buffer = reader.readNext();
-                    String message = new String(buffer.array(), 
buffer.arrayOffset(),
-                            buffer.remaining(), StandardCharsets.UTF_8);
+                    String message = parseValue(buffer);
                     if (i % logFreq == 0) {
                       LOG.info(logName + " Read " + message);
                     }
diff --git 
a/ratis-logservice/src/test/java/org/apache/ratis/logservice/tool/TestVerificationTool.java
 
b/ratis-logservice/src/test/java/org/apache/ratis/logservice/tool/TestVerificationTool.java
new file mode 100644
index 0000000..617f763
--- /dev/null
+++ 
b/ratis-logservice/src/test/java/org/apache/ratis/logservice/tool/TestVerificationTool.java
@@ -0,0 +1,59 @@
+/**
+ * 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.ratis.logservice.tool;
+
+import static org.junit.Assert.assertEquals;
+
+import java.nio.ByteBuffer;
+
+import org.apache.ratis.logservice.api.LogName;
+import org.apache.ratis.logservice.client.LogServiceClient;
+import org.apache.ratis.logservice.tool.VerificationTool.Operation;
+import org.junit.Test;
+
+public class TestVerificationTool {
+
+  private static class MockOperation extends Operation {
+
+    MockOperation(LogName logName, LogServiceClient client, int numRecords, 
int logFreq, int valueSize) {
+      super(logName, client, numRecords, logFreq, valueSize);
+    }
+
+    @Override public void run() {
+      throw new UnsupportedOperationException();
+    }
+  }
+
+  Operation createOp(int valueSize) {
+    return new MockOperation(null, null, 1, 1, valueSize);
+  }
+
+  @Test
+  public void testValueSerialization() {
+    // Test that, for value sizes from 0 to 50 bytes, we can generate correct 
values.
+    for (int i = 0; i < 50; i++) {
+      Operation op = createOp(i);
+      String value = VerificationTool.MESSAGE_PREFIX + i;
+      ByteBuffer serialized = op.createValue(value);
+      assertEquals(i, serialized.limit() - serialized.arrayOffset());
+      assertEquals(value.substring(0, Math.min(i, value.length())), 
op.parseValue(serialized));
+    }
+    
+  }
+
+}

Reply via email to