diff --git a/core/src/main/java/org/apache/accumulo/core/fate/zookeeper/FateLock.java b/core/src/main/java/org/apache/accumulo/core/fate/zookeeper/FateLock.java index 5e8c5418185..fcd02f3bd40 100644 --- a/core/src/main/java/org/apache/accumulo/core/fate/zookeeper/FateLock.java +++ b/core/src/main/java/org/apache/accumulo/core/fate/zookeeper/FateLock.java @@ -74,7 +74,7 @@ public String toString() { public final static class FateLockEntry { - private static final String DELIMITER = "_"; + private static final String DELIMITER = "~"; final LockType lockType; final FateId fateId; @@ -87,7 +87,8 @@ private FateLockEntry(LockType lockType, FateId fateId, LockRange range) { } private FateLockEntry(String entry) { - var fields = entry.split(DELIMITER, 4); + var fields = entry.split(DELIMITER); + Preconditions.checkArgument(fields.length == 4, entry); this.lockType = LockType.valueOf(fields[0]); this.fateId = FateId.from(fields[1]); this.range = LockRange.of(decodeRow(fields[2]), decodeRow(fields[3])); @@ -109,13 +110,13 @@ private String encodeRow(Text row) { if (row == null) { return "N"; } else { - return "P" + Base64.getEncoder().encodeToString(TextUtil.getBytes(row)); + return "P" + Base64.getUrlEncoder().encodeToString(TextUtil.getBytes(row)); } } private Text decodeRow(String enc) { if (enc.charAt(0) == 'P') { - return new Text(Base64.getDecoder().decode(enc.substring(1))); + return new Text(Base64.getUrlDecoder().decode(enc.substring(1))); } else if (enc.charAt(0) == 'N') { return null; } else { @@ -123,9 +124,15 @@ private Text decodeRow(String enc) { } } + private String checkForDelimiter(String s) { + Preconditions.checkArgument(!s.contains(DELIMITER), s); + return s; + } + public String serialize() { - return lockType.name() + DELIMITER + fateId.canonical() + DELIMITER - + encodeRow(range.getStartRow()) + DELIMITER + encodeRow(range.getEndRow()); + return checkForDelimiter(lockType.name()) + DELIMITER + checkForDelimiter(fateId.canonical()) + + DELIMITER + checkForDelimiter(encodeRow(range.getStartRow())) + DELIMITER + + checkForDelimiter(encodeRow(range.getEndRow())); } public static FateLockEntry from(LockType lockType, FateId fateId, LockRange range) { @@ -183,19 +190,21 @@ public final static class NodeName { public long addEntry(FateLockEntry entry) { String dataString = entry.serialize(); - Preconditions.checkState(!dataString.contains("#")); + Preconditions.checkState(!dataString.contains("#") && !dataString.contains("/"), dataString); String newPath; try { while (true) { try { - newPath = - zoo.putPersistentSequential(path + "/" + PREFIX + dataString + "#", new byte[0]); + var prefix = path + "/" + PREFIX + dataString + "#"; + log.trace("Attempting to create {} in zookeeper", prefix); + newPath = zoo.putPersistentSequential(prefix, new byte[0]); String[] parts = newPath.split("/"); String last = parts[parts.length - 1]; return new NodeName(last).sequence; } catch (NoNodeException nne) { // the parent does not exist so try to create it + log.trace("Attempting to create parent {}", path.toString(), nne); zoo.putPersistentData(path.toString(), new byte[] {}, NodeExistsPolicy.SKIP); } } diff --git a/core/src/test/java/org/apache/accumulo/core/fate/zookeeper/FateLockTest.java b/core/src/test/java/org/apache/accumulo/core/fate/zookeeper/FateLockTest.java index 3ae75e33af6..eea6f610acf 100644 --- a/core/src/test/java/org/apache/accumulo/core/fate/zookeeper/FateLockTest.java +++ b/core/src/test/java/org/apache/accumulo/core/fate/zookeeper/FateLockTest.java @@ -34,7 +34,7 @@ public class FateLockTest { public void testParsing() { var fateId = FateId.from(FateInstanceType.USER, UUID.randomUUID()); // ZooKeeper docs state that sequence numbers are formatted using %010d - String lockData = "WRITE_" + fateId.canonical() + "_N_N"; + String lockData = "WRITE~" + fateId.canonical() + "~N~N"; var lockNode = new FateLock.NodeName(FateLock.PREFIX + lockData + "#" + String.format("%010d", 40)); assertEquals(40, lockNode.sequence);