All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.vertx.spi.cluster.zookeeper.impl.ZKSyncMap Maven / Gradle / Ivy

The newest version!
/*
 *  Copyright (c) 2011-2016 The original author or authors
 *  ------------------------------------------------------
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the Eclipse Public License v1.0
 *  and Apache License v2.0 which accompanies this distribution.
 *
 *       The Eclipse Public License is available at
 *       http://www.eclipse.org/legal/epl-v10.html
 *
 *       The Apache License v2.0 is available at
 *       http://www.opensource.org/licenses/apache2.0.php
 *
 *  You may elect to redistribute this code under either of these licenses.
 */
package io.vertx.spi.cluster.zookeeper.impl;

import io.vertx.core.VertxException;
import io.vertx.core.internal.logging.Logger;
import io.vertx.core.internal.logging.LoggerFactory;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.api.CuratorEventType;
import org.apache.curator.framework.imps.CuratorFrameworkState;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * Created by Stream.Liu
 */
public class ZKSyncMap extends ZKMap implements Map {

  private static final Logger logger = LoggerFactory.getLogger(ZKSyncMap.class);

  public ZKSyncMap(CuratorFramework curator, String mapName) {
    super(curator, null, ZK_PATH_SYNC_MAP, mapName);
  }

  @Override
  public int size() {
    try {
      return curator.getChildren().forPath(mapPath).size();
    } catch (Exception e) {
      throw new VertxException(e);
    }
  }

  @Override
  public boolean isEmpty() {
    try {
      syncKeyPath(mapPath);
      return curator.getChildren().forPath(mapPath).isEmpty();
    } catch (Exception e) {
      throw new VertxException(e);
    }
  }

  @Override
  public boolean containsKey(Object key) {
    try {
      String keyPath = keyPath((K) key);
      syncKeyPath(keyPath);
      return curator.checkExists().forPath(keyPath) != null;
    } catch (Exception e) {
      throw new VertxException(e);
    }
  }

  @Override
  public boolean containsValue(Object value) {
    try {
      syncKeyPath(mapPath);
      return curator.getChildren().forPath(mapPath).stream().anyMatch(k -> {
        try {
          byte[] bytes = curator.getData().forPath(keyPath((K) k));
          KeyValue keyValue = asObject(bytes);
          return keyValue.getValue().equals(value);
        } catch (Exception ex) {
          throw new VertxException(ex);
        }
      });
    } catch (Exception e) {
      throw new VertxException(e);
    }
  }

  @Override
  public V get(Object key) {
    try {
      String keyPath = keyPath((K) key);
      syncKeyPath(keyPath);
      if (null == curator.checkExists().forPath(keyPath)) {
        return null;
      } else {
        KeyValue keyValue = asObject(curator.getData().forPath(keyPath));
        return keyValue.getValue();
      }
    } catch (Exception e) {
      if (e instanceof VertxException && e.getCause() instanceof KeeperException.NoNodeException) {
        logger.warn("zookeeper node lost. " + e.getCause().getMessage());
      } else {
        throw new VertxException(e);
      }
    }
    return null;
  }

  @Override
  public V put(K key, V value) {
    try {
      String keyPath = keyPath(key);
      KeyValue keyValue = new KeyValue<>(key, value);
      byte[] valueBytes = asByte(keyValue);
      if (get(key) != null) {
        curator.setData().forPath(keyPath, valueBytes);
      } else {
        curator.create().creatingParentsIfNeeded().withMode(CreateMode.CONTAINER).forPath(keyPath, valueBytes);
      }
      return value;
    } catch (Exception e) {
      throw new VertxException(e);
    }
  }

  @Override
  public V remove(Object key) {
    try {
      V result = get(key);
      if (result != null) curator.delete().deletingChildrenIfNeeded().forPath(keyPath((K) key));
      return result;
    } catch (Exception e) {
      throw new VertxException(e);
    }
  }

  @Override
  public void putAll(Map m) {
    m.entrySet().stream().forEach(entry -> put(entry.getKey(), entry.getValue()));
  }

  @Override
  public void clear() {
    try {
      curator.delete().deletingChildrenIfNeeded().forPath(mapPath);
      curator.create().creatingParentsIfNeeded().withMode(CreateMode.CONTAINER).forPath(mapPath);
    } catch (Exception e) {
      throw new VertxException(e);
    }
  }

  @Override
  public Set keySet() {
    try {
      syncKeyPath(mapPath);
      return curator.getChildren().forPath(mapPath).stream().map(k -> {
        try {
          KeyValue keyValue = asObject(curator.getData().forPath(keyPath((K) k)));
          return keyValue.getKey();
        } catch (KeeperException.NoNodeException nodeLostEx) {
          logger.warn("node lost " + nodeLostEx.getMessage());
          return null;
        } catch (Exception ex) {
          throw new VertxException(ex);
        }
      }).collect(Collectors.toSet());
    } catch (Exception ex) {
      throw new VertxException(ex);
    }
  }

  @Override
  public Collection values() {
    try {
      syncKeyPath(mapPath);
      return curator.getChildren().forPath(mapPath).stream()
        .map(k -> {
            try {
              KeyValue keyValue = asObject(curator.getData().forPath(keyPath((K) k)));
              return keyValue.getValue();
            } catch (Exception ex) {
              throw new VertxException(ex);
            }
          }
        ).collect(Collectors.toSet());
    } catch (Exception ex) {
      throw new VertxException(ex);
    }
  }

  private void syncKeyPath(String path) {
    //sync always run in background, so we have to using latch to wait callback.
    CountDownLatch latch = new CountDownLatch(1);
    try {
      curator.sync().inBackground((client, event) -> {
        if (client.getState() == CuratorFrameworkState.STOPPED) {
          latch.countDown();
          return;
        }
        if (event.getPath().equals(path) && event.getType() == CuratorEventType.SYNC) {
          latch.countDown();
        }
      }).forPath(path);
      latch.await(3L, TimeUnit.SECONDS);
    } catch (Exception e) {
      if (e instanceof InterruptedException) {
        Thread.currentThread().interrupt();
      }
      if (!(e instanceof KeeperException.NoNodeException)) {
        throw new VertxException(e);
      }
    }
  }

  @Override
  public Set> entrySet() {
    return keySet().stream().map(k -> {
      V v = get(k);
      return new HashMap.SimpleImmutableEntry<>(k, v);
    }).collect(Collectors.toSet());
  }

  static class KeyValue implements Serializable {
    private static final long serialVersionUID = 6529685098267757690L;
    private K key;
    private V value;

    public KeyValue(K key, V value) {
      this.key = key;
      this.value = value;
    }

    public K getKey() {
      return key;
    }

    public V getValue() {
      return value;
    }
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy