package org.apache.blur.zookeeper;
/**
* 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.
*/
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.apache.blur.log.Log;
import org.apache.blur.log.LogFactory;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
public class ZooKeeperLockManager {
private static final Log LOG = LogFactory.getLog(ZooKeeperLockManager.class);
protected final Map<String, String> _lockMap = new HashMap<String, String>();
protected final String _lockPath;
protected final ZooKeeper _zooKeeper;
protected final Object _lock = new Object();
protected final long _timeout;
protected final Watcher _watcher = new Watcher() {
@Override
public void process(WatchedEvent event) {
synchronized (_lock) {
_lock.notify();
}
}
};
public ZooKeeperLockManager(ZooKeeper zooKeeper, String lockPath) {
_zooKeeper = zooKeeper;
_lockPath = lockPath;
_timeout = TimeUnit.SECONDS.toMillis(1);
}
public int getNumberOfLockNodesPresent(String name) throws KeeperException, InterruptedException {
List<String> children = _zooKeeper.getChildren(_lockPath, false);
int count = 0;
for (String s : children) {
if (s.startsWith(name + "_")) {
count++;
}
}
return count;
}
public void unlock(String name) throws InterruptedException, KeeperException {
if (!_lockMap.containsKey(name)) {
throw new RuntimeException("Lock [" + name + "] has not be created.");
}
String lockPath = _lockMap.remove(name);
LOG.debug("Unlocking on path [" + lockPath + "] with name [" + name + "]");
_zooKeeper.delete(lockPath, -1);
}
public void lock(String name) throws KeeperException, InterruptedException {
if (_lockMap.containsKey(name)) {
throw new RuntimeException("Lock [" + name + "] already created.");
}
String newPath = _zooKeeper.create(_lockPath + "/" + name + "_", null, Ids.OPEN_ACL_UNSAFE,
CreateMode.EPHEMERAL_SEQUENTIAL);
_lockMap.put(name, newPath);
while (true) {
synchronized (_lock) {
List<String> children = getOnlyThisLocksChildren(name, _zooKeeper.getChildren(_lockPath, _watcher));
Collections.sort(children);
String firstElement = children.get(0);
if ((_lockPath + "/" + firstElement).equals(newPath)) {
// yay!, we got the lock
LOG.debug("Lock on path [" + _lockPath + "] with name [" + name + "]");
return;
} else {
LOG.debug("Waiting for lock on path [" + _lockPath + "] with name [" + name + "]");
_lock.wait(_timeout);
}
}
}
}
private List<String> getOnlyThisLocksChildren(String name, List<String> children) {
List<String> result = new ArrayList<String>();
for (String c : children) {
if (c.startsWith(name + "_")) {
result.add(c);
}
}
return result;
}
}