public synchronized void clear() { globalLock.lock(); try { reloadCacheIfNeeded(); clearInternal(); } finally { globalLock.unlock(); } }
private synchronized String getItemNodePath(String key) { return getNodePath(key); }
public synchronized T put(String key, T value) { globalLock.lock(); try { reloadCacheIfNeeded(); return putInternal(key, value); } finally { globalLock.unlock(); } }
@Override public synchronized T remove(Object key) { globalLock.lock(); try { reloadCacheIfNeeded(); return removeInternal(key); } finally { globalLock.unlock(); } }
SynchronizedZKMap<String> map1 = new SynchronizedZKMap<String>(zkClient, path, Serializers.stringSerializer()); SynchronizedZKMap<String> map2 = new SynchronizedZKMap<String>(zkClient, path, Serializers.stringSerializer()); Assert.assertEquals(0, map1.size()); Assert.assertEquals(0, map2.size()); map2.remove("foo"); TimeUnit.MILLISECONDS.sleep(10); Assert.assertEquals(0, map1.size()); Assert.assertEquals(0, map2.size()); map1.put("key1", "value1"); map2.put("key2", "value2"); map1.put("key3", "value3"); TimeUnit.MILLISECONDS.sleep(10); Assert.assertEquals(3, map1.size()); Assert.assertEquals("value1", map1.get("key1")); Assert.assertEquals("value2", map1.get("key2")); Assert.assertEquals("value3", map1.get("key3")); Assert.assertEquals(3, map2.size()); Assert.assertEquals("value1", map2.get("key1")); Assert.assertEquals("value2", map2.get("key2")); Assert.assertEquals("value3", map2.get("key3")); map1.put("key2", "value2_m"); TimeUnit.MILLISECONDS.sleep(10); Assert.assertEquals(3, map1.size()); Assert.assertEquals("value2_m", map1.get("key2")); Assert.assertEquals(3, map2.size()); Assert.assertEquals("value2_m", map2.get("key2"));
@Override public synchronized boolean isEmpty() { globalLock.lock(); try { reloadCacheIfNeeded(); return currentView.isEmpty(); } finally { globalLock.unlock(); } }
public ZKElementsTracking(final ZKClient zkClient, final String basePath) { String queuePath = basePath + "/queue"; Futures.getUnchecked(ZKClientExt.ensureExists(zkClient, queuePath)); this.queueElements = new SynchronizedZKMap<Entry>(zkClient, queuePath + "/map", ENTRY_SERIALIZER); this.globalLock = new ThreadLocal<Lock>() { @Override protected Lock initialValue() { return new ReentrantDistributedLock(zkClient, basePath); } }; }
private T removeInternal(Object key) { if (!(key instanceof String)) { throw new IllegalArgumentException("Expected key of type java.lang.String but was " + (key == null ? null : key.getClass())); } if (!currentView.containsKey(key)) { return null; } Map<String, T> current = Maps.newHashMap(currentView); T removed = current.remove(key); currentView = ImmutableMap.<String, T>builder().putAll(current).build(); // note: we cannot only issue remove from zk if removed != null because even if removed == null this could mean // the element was removed (and for other race-condition reasons) Futures.getUnchecked(ZKClientExt.delete(zkClient, getItemNodePath((String) key), true)); return removed; }
@Override public synchronized boolean containsValue(Object value) { globalLock.lock(); try { reloadCacheIfNeeded(); return currentView.containsValue(value); } finally { globalLock.unlock(); } }
Thread[] producerThreads = new Thread[workersCount]; for (int i = 0; i < workersCount; i++) { SynchronizedZKMap<String> map = new SynchronizedZKMap<String>(zkClient, "/map", Serializers.stringSerializer()); producers[i] = new Producer(map); producerThreads[i] = new Thread(producers[i]); Thread[] consumerThreads = new Thread[workersCount]; for (int i = 0; i < workersCount; i++) { SynchronizedZKMap<String> map = new SynchronizedZKMap<String>(zkClient, "/map", Serializers.stringSerializer()); consumers[i] = new Consumer(map); consumerThreads[i] = new Thread(consumers[i]);
private T putInternal(String key, T value) { Map<String, T> current = Maps.newHashMap(currentView); T result = current.put(key, value); currentView = ImmutableMap.<String, T>builder().putAll(current).build(); String itemNodePath = getItemNodePath(key); // Note: we do delete and add new node with new data VS createOrSet() so that cversion of children change (we depend // on it when checking if the current in-memory view is stale) Futures.getUnchecked(ZKClientExt.delete(zkClient, itemNodePath, true)); Futures.getUnchecked(zkClient.create(itemNodePath, serializer.serialize(value), CreateMode.PERSISTENT, true)); return result; }
@Override public synchronized Collection<T> values() { globalLock.lock(); try { reloadCacheIfNeeded(); return currentView.values(); } finally { globalLock.unlock(); } }
private void clearInternal() { if (currentView.size() > 0) { currentView = Collections.emptyMap(); NodeChildren nodeChildren = Futures.getUnchecked(zkClient.getChildren(ENTRIES_PATH)); List<ListenableFuture<String>> deleteFutures = Lists.newArrayList(); for (String node : nodeChildren.getChildren()) { deleteFutures.add(ZKClientExt.delete(zkClient, getNodePath(node), true)); } Futures.getUnchecked(Futures.allAsList(deleteFutures)); } }
@Override public synchronized boolean containsKey(Object key) { globalLock.lock(); try { reloadCacheIfNeeded(); return currentView.containsKey(key); } finally { globalLock.unlock(); } }
private void reloadCacheIfNeeded() { NodeChildren nodeChildren = Futures.getUnchecked(ZKClientExt.getChildrenOrNull(zkClient, ENTRIES_PATH)); if (nodeChildren == null) { if (currentView.size() > 0) { currentView = Collections.emptyMap(); } return; } // we use children version to detect if we need to update local view int trueVersion = nodeChildren.getStat().getCversion(); if (currentViewVersion == trueVersion) { return; } List<String> nodes = nodeChildren.getChildren(); final Map<String, ListenableFuture<NodeData>> nodeAndDataFutures = Maps.newHashMap(); List<OperationFuture<NodeData>> dataFutures = Lists.newArrayList(); for (String node : nodes) { OperationFuture<NodeData> dataFuture = zkClient.getData(getNodePath(node)); dataFutures.add(dataFuture); nodeAndDataFutures.put(node, dataFuture); } Futures.getUnchecked(Futures.successfulAsList(dataFutures)); ImmutableMap.Builder<String, T> builder = ImmutableMap.builder(); for (Entry<String, ListenableFuture<NodeData>> nodeAndData : nodeAndDataFutures.entrySet()) { T value = serializer.deserialize(Futures.getUnchecked(nodeAndData.getValue()).getData()); builder.put(nodeAndData.getKey(), value); } currentView = builder.build(); currentViewVersion = trueVersion; }
@Override public synchronized Set<Entry<String, T>> entrySet() { globalLock.lock(); try { reloadCacheIfNeeded(); return currentView.entrySet(); } finally { globalLock.unlock(); } }
@Override public synchronized int size() { globalLock.lock(); try { reloadCacheIfNeeded(); return currentView.size(); } finally { globalLock.unlock(); } }
@Override public synchronized T get(Object key) { globalLock.lock(); try { reloadCacheIfNeeded(); return currentView.get(key); } finally { globalLock.unlock(); } }
@Override public synchronized Set<String> keySet() { globalLock.lock(); try { reloadCacheIfNeeded(); return currentView.keySet(); } finally { globalLock.unlock(); } }