From 82c541bba79464f37383a57f3f55f91eebde13ce Mon Sep 17 00:00:00 2001 From: Jeff Meunier Date: Tue, 17 Sep 2019 15:41:35 -0400 Subject: [PATCH 1/2] Added code to optionall write a string to the writeLock file. --- src/main/java/com/upserve/uppend/FileStore.java | 16 ++++++++++++++-- .../com/upserve/uppend/FileStoreBuilder.java | 11 +++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/upserve/uppend/FileStore.java b/src/main/java/com/upserve/uppend/FileStore.java index 51191b2a..4990dadb 100644 --- a/src/main/java/com/upserve/uppend/FileStore.java +++ b/src/main/java/com/upserve/uppend/FileStore.java @@ -8,6 +8,7 @@ import java.io.*; import java.lang.invoke.MethodHandles; +import java.nio.ByteBuffer; import java.nio.channels.*; import java.nio.charset.StandardCharsets; import java.nio.file.*; @@ -80,10 +81,21 @@ abstract class FileStore implements AutoCloseable, Register this.readOnly = readOnly; lockPath = readOnly ? dir.resolve("readLock") : dir.resolve("writeLock"); - try { lockChan = FileChannel.open(lockPath, StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE); - lock = readOnly ? lockChan.lock(0L, Long.MAX_VALUE, true) : lockChan.lock(); // Write lock is exclusive + if(readOnly) { + // this is a readLock + lock = lockChan.lock(0L, Long.MAX_VALUE, true); + } else { + // this is an exclusive writeLock + lock = lockChan.lock(); + String writeLockContentString = builder.getWriteLockContentString(); + if(writeLockContentString != null) { + ByteBuffer byteBuf = ByteBuffer.wrap(writeLockContentString.getBytes()); + lockChan.write(byteBuf); + lockChan.force(false); + } + } } catch (IOException e) { throw new UncheckedIOException("unable to open lock: " + lockPath, e); } catch (OverlappingFileLockException e) { diff --git a/src/main/java/com/upserve/uppend/FileStoreBuilder.java b/src/main/java/com/upserve/uppend/FileStoreBuilder.java index a40c1835..f0817bbc 100644 --- a/src/main/java/com/upserve/uppend/FileStoreBuilder.java +++ b/src/main/java/com/upserve/uppend/FileStoreBuilder.java @@ -28,6 +28,8 @@ public class FileStoreBuilder> { private int targetBufferSize = TARGET_PRODUCTION_BUFFER_SIZE; + private String writeLockContentString = null; + // Store Options public static final int DEFAULT_FLUSH_DELAY_SECONDS = 30; public static final int DEFAULT_FLUSH_THRESHOLD = 1000; @@ -76,6 +78,12 @@ public T withTargetBufferSize(int targetBufferSize) { return (T) this; } + @SuppressWarnings("unchecked") + public T withWriteLockContentString(String writeLockContentString) { + this.writeLockContentString = writeLockContentString; + return (T) this; + } + // Append Store Options @SuppressWarnings("unchecked") public T withStoreName(String storeName) { @@ -179,6 +187,8 @@ public String getStoreName() { public String getMetricsRootName(){ return metricsRootName; } + public String getWriteLockContentString() { return writeLockContentString; } + public LookupDataMetrics.Adders getLookupDataMetricsAdders(){ return lookupDataMetricsAdders; } public MutableBlobStoreMetrics.Adders getMutableBlobStoreMetricsAdders() { return mutableBlobStoreMetricsAdders; } @@ -203,6 +213,7 @@ public String toString() { ", storeMetrics=" + storeMetrics + ", cacheMetricsRegistry=" + cacheMetricsRegistry + ", cacheMetrics=" + cacheMetrics + + ", writeLockContentString='" + writeLockContentString + "'" + '}'; } } From 75877e8d28a4f081efd4ced41f9277ee32b164f5 Mon Sep 17 00:00:00 2001 From: Jeff Meunier Date: Wed, 18 Sep 2019 14:40:36 -0400 Subject: [PATCH 2/2] Added two tests: one to ensure that a specified string is written to the writeLock file, and another to ensure that nothing is written to the readLock file. --- .../com/upserve/uppend/FileStoreTest.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/test/java/com/upserve/uppend/FileStoreTest.java b/src/test/java/com/upserve/uppend/FileStoreTest.java index 2a88b8a3..511c9d3a 100644 --- a/src/test/java/com/upserve/uppend/FileStoreTest.java +++ b/src/test/java/com/upserve/uppend/FileStoreTest.java @@ -7,7 +7,9 @@ import java.nio.ByteBuffer; import java.nio.file.*; import java.util.*; +import java.util.regex.Pattern; import java.util.stream.Collectors; +import java.util.stream.Stream; import static org.junit.Assert.*; @@ -197,6 +199,28 @@ public void testCreateDirectoriesWithParentSymlink() throws Exception { SafeDeleting.removeDirectory(base); } + @Test + public void testLockFileAndContent_readWrite() throws IOException { + String expectedWriteLockContent = "write lock message"; + MyFileStore v = new MyFileStore(path, 1, expectedWriteLockContent); + Path writeLockFilePath = Paths.get(path.toString(), "writeLock"); + try (FileReader fr = new FileReader(writeLockFilePath.toString()); + BufferedReader br = new BufferedReader(fr)) { + String writeLockContent = br.readLine(); + assertTrue(Pattern.matches(expectedWriteLockContent, writeLockContent)); + } + SafeDeleting.removeDirectory(path); + } + + @Test + public void testLockFileAndContent_readOnly() throws IOException { + MyFileStore v = new MyFileStore(path, 1, true); + Path readLockFilePath = Paths.get(path.toString(), "readLock"); + File file = readLockFilePath.toFile(); + assertEquals(0, file.length()); + SafeDeleting.removeDirectory(path); + } + @Test public void testReaderWriter() throws InterruptedException { @@ -253,5 +277,14 @@ private class MyFileStore extends FileAppendOnlyStore { .withMetadataTTL(30) ); } + + MyFileStore(Path dir, int numPartitions, String writeLockContentString) { + super(false, new AppendOnlyStoreBuilder() + .withDir(dir) + .withPartitionCount(numPartitions) + .withMetadataTTL(30) + .withWriteLockContentString(writeLockContentString) + ); + } } }