<commit_before>/*
 * arcus-java-client : Arcus Java client
 * Copyright 2010-2014 NAVER Corp.
 *
 * Licensed 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.
 */
package net.spy.memcached;

/**
 * A program to use CacheMonitor to start and
 * stop memcached node based on a znode. The program watches the
 * specified znode and saves the znode that corresponds to the
 * memcached server in the remote machine. It also changes the 
 * previous ketama node
 */
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import net.spy.memcached.ArcusClientException.InitializeClientException;
import net.spy.memcached.compat.SpyThread;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.ZooDefs.Ids;

public class CacheManager extends SpyThread implements Watcher,
		CacheMonitor.CacheMonitorListener {
	private static final String ARCUS_BASE_CACHE_LIST_ZPATH = "/arcus/cache_list/";

	private static final String ARCUS_BASE_CLIENT_INFO_ZPATH = "/arcus/client_list/";

	private static final int ZK_SESSION_TIMEOUT = 15000;
	
	private static final long ZK_CONNECT_TIMEOUT = ZK_SESSION_TIMEOUT;

	private final String hostPort;

	private final String serviceCode;

	private CacheMonitor cacheMonitor;

	private ZooKeeper zk;

	private ArcusClient[] client;

	private final CountDownLatch clientInitLatch;

	private final ConnectionFactoryBuilder cfb;

	private final int waitTimeForConnect;

	private final int poolSize;

	private volatile boolean shutdownRequested = false;

	private CountDownLatch zkInitLatch;

	private List<String> prevChildren;

	/**
	 * The locator class of the spymemcached has an assumption
	 * that it should have one cache node at least. 
	 * Thus, we add a fake server node in it
	 * if there's no cache servers for the given service code.
	 * This is just a work-around, but it works really. 
	 */
	public static final String FAKE_SERVER_NODE = "0.0.0.0:23456";

	public CacheManager(String hostPort, String serviceCode,
			ConnectionFactoryBuilder cfb, CountDownLatch clientInitLatch, int poolSize,
			int waitTimeForConnect) {

		this.hostPort = hostPort;
		this.serviceCode = serviceCode;
		this.cfb = cfb;
		this.clientInitLatch = clientInitLatch;
		this.poolSize = poolSize;
		this.waitTimeForConnect = waitTimeForConnect;

		initZooKeeperClient();

		setName("Cache Manager IO for " + serviceCode + "@" + hostPort);
		setDaemon(true);
		start();

		getLogger().info("CacheManager started. (" + serviceCode + "@" + hostPort + ")");
		
	}
	
	private void initZooKeeperClient() {
		try {
			getLogger().info("Trying to connect to Arcus admin(%s@%s)", serviceCode, hostPort);
			
			zkInitLatch = new CountDownLatch(1);
			zk = new ZooKeeper(hostPort, ZK_SESSION_TIMEOUT, this);

			try {
				/* In the above ZooKeeper() internals, reverse DNS lookup occurs
				 * when the getHostName() of InetSocketAddress class is called.
				 * In Windows, the reverse DNS lookup includes NetBIOS lookup
				 * that bring delay of 5 seconds (as well as dns and host file lookup).
				 * So, ZK_CONNECT_TIMEOUT is set as much like ZK session timeout.
				 */
				if (zkInitLatch.await(ZK_CONNECT_TIMEOUT, TimeUnit.MILLISECONDS) == false) {
					getLogger().fatal("Connecting to Arcus admin(%s) timed out : %d miliseconds",
									hostPort, ZK_CONNECT_TIMEOUT);
					throw new AdminConnectTimeoutException(hostPort);
				}
				
				if (zk.exists(ARCUS_BASE_CACHE_LIST_ZPATH + serviceCode, false) == null) {
					getLogger().fatal("Service code not found. (" + serviceCode + ")");
					throw new NotExistsServiceCodeException(serviceCode);
				}

				String path = getClientInfo();
				if (path.isEmpty()) {
					getLogger().fatal("Can't create the znode of client info (" + path + ")");
					throw new InitializeClientException("Can't initialize Arcus client.");
				}
				
				if (zk.exists(path, false) == null) {
					zk.create(path, null, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
				}
			} catch (AdminConnectTimeoutException e) {
				shutdownZooKeeperClient();
				throw e;
			} catch (NotExistsServiceCodeException e) {
				shutdownZooKeeperClient();
				throw e;
			} catch (InterruptedException ie) {
				getLogger().fatal("Can't connect to Arcus admin(%s@%s) %s",
								serviceCode, hostPort, ie.getMessage());
				shutdownZooKeeperClient();
				return;
			} catch (Exception e) {
				getLogger().fatal("Unexpected exception. contact to Arcus administrator");

				shutdownZooKeeperClient();
				throw new InitializeClientException("Can't initialize Arcus client.", e);
			}

			cacheMonitor = new CacheMonitor(zk, ARCUS_BASE_CACHE_LIST_ZPATH, serviceCode, this);
		} catch (IOException e) {
			throw new InitializeClientException("Can't initialize Arcus client.", e);
		}
	}

	private String getClientInfo() {
		String path = "";
		
		try {
			SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
			Date currentTime = new Date();
			
			// create the ephemeral znode 
			// "/arcus/client_list/{service_code}/{client hostname}_{ip address}_{pool size}_java_{client version}_{YYYYMMDDHHIISS}_{zk session id}"
			path = ARCUS_BASE_CLIENT_INFO_ZPATH + serviceCode + "/";
			path = path 
				 + InetAddress.getLocalHost().getHostName() + "_"
				 + InetAddress.getLocalHost().getHostAddress() + "_"
				 + this.poolSize + "_java_" + ArcusClient.VERSION + "_"
				 + simpleDateFormat.format(currentTime) + "_" 
				 + zk.getSessionId();
			
		} catch (UnknownHostException e) {
			return null;
		}<commit_msg>add error handling that get client info and create znode of client info<commit_after>/*
 * arcus-java-client : Arcus Java client
 * Copyright 2010-2014 NAVER Corp.
 *
 * Licensed 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.
 */
package net.spy.memcached;

/**
 * A program to use CacheMonitor to start and
 * stop memcached node based on a znode. The program watches the
 * specified znode and saves the znode that corresponds to the
 * memcached server in the remote machine. It also changes the 
 * previous ketama node
 */
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import net.spy.memcached.ArcusClientException.InitializeClientException;
import net.spy.memcached.compat.SpyThread;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.ZooDefs.Ids;

public class CacheManager extends SpyThread implements Watcher,
		CacheMonitor.CacheMonitorListener {
	private static final String ARCUS_BASE_CACHE_LIST_ZPATH = "/arcus/cache_list/";

	private static final String ARCUS_BASE_CLIENT_INFO_ZPATH = "/arcus/client_list/";

	private static final int ZK_SESSION_TIMEOUT = 15000;
	
	private static final long ZK_CONNECT_TIMEOUT = ZK_SESSION_TIMEOUT;

	private final String hostPort;

	private final String serviceCode;

	private CacheMonitor cacheMonitor;

	private ZooKeeper zk;

	private ArcusClient[] client;

	private final CountDownLatch clientInitLatch;

	private final ConnectionFactoryBuilder cfb;

	private final int waitTimeForConnect;

	private final int poolSize;

	private volatile boolean shutdownRequested = false;

	private CountDownLatch zkInitLatch;

	private List<String> prevChildren;

	/**
	 * The locator class of the spymemcached has an assumption
	 * that it should have one cache node at least. 
	 * Thus, we add a fake server node in it
	 * if there's no cache servers for the given service code.
	 * This is just a work-around, but it works really. 
	 */
	public static final String FAKE_SERVER_NODE = "0.0.0.0:23456";

	public CacheManager(String hostPort, String serviceCode,
			ConnectionFactoryBuilder cfb, CountDownLatch clientInitLatch, int poolSize,
			int waitTimeForConnect) {

		this.hostPort = hostPort;
		this.serviceCode = serviceCode;
		this.cfb = cfb;
		this.clientInitLatch = clientInitLatch;
		this.poolSize = poolSize;
		this.waitTimeForConnect = waitTimeForConnect;

		initZooKeeperClient();

		setName("Cache Manager IO for " + serviceCode + "@" + hostPort);
		setDaemon(true);
		start();

		getLogger().info("CacheManager started. (" + serviceCode + "@" + hostPort + ")");
		
	}
	
	private void initZooKeeperClient() {
		try {
			getLogger().info("Trying to connect to Arcus admin(%s@%s)", serviceCode, hostPort);
			
			zkInitLatch = new CountDownLatch(1);
			zk = new ZooKeeper(hostPort, ZK_SESSION_TIMEOUT, this);

			try {
				/* In the above ZooKeeper() internals, reverse DNS lookup occurs
				 * when the getHostName() of InetSocketAddress class is called.
				 * In Windows, the reverse DNS lookup includes NetBIOS lookup
				 * that bring delay of 5 seconds (as well as dns and host file lookup).
				 * So, ZK_CONNECT_TIMEOUT is set as much like ZK session timeout.
				 */
				if (zkInitLatch.await(ZK_CONNECT_TIMEOUT, TimeUnit.MILLISECONDS) == false) {
					getLogger().fatal("Connecting to Arcus admin(%s) timed out : %d miliseconds",
									hostPort, ZK_CONNECT_TIMEOUT);
					throw new AdminConnectTimeoutException(hostPort);
				}
				
				if (zk.exists(ARCUS_BASE_CACHE_LIST_ZPATH + serviceCode, false) == null) {
					getLogger().fatal("Service code not found. (" + serviceCode + ")");
					throw new NotExistsServiceCodeException(serviceCode);
				}

				String path = getClientInfo();
				if (path.isEmpty()) {
					getLogger().fatal("Can't create the znode of client info (" + path + ")");
				} else {
					if (zk.exists(path, false) == null) {
						zk.create(path, null, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
					}
				}
			} catch (AdminConnectTimeoutException e) {
				shutdownZooKeeperClient();
				throw e;
			} catch (NotExistsServiceCodeException e) {
				shutdownZooKeeperClient();
				throw e;
			} catch (InterruptedException ie) {
				getLogger().fatal("Can't connect to Arcus admin(%s@%s) %s",
								serviceCode, hostPort, ie.getMessage());
				shutdownZooKeeperClient();
				return;
			} catch (Exception e) {
				getLogger().fatal("Unexpected exception. contact to Arcus administrator", e);

				shutdownZooKeeperClient();
				throw new InitializeClientException("Can't initialize Arcus client.", e);
			}

			cacheMonitor = new CacheMonitor(zk, ARCUS_BASE_CACHE_LIST_ZPATH, serviceCode, this);
		} catch (IOException e) {
			throw new InitializeClientException("Can't initialize Arcus client.", e);
		}
	}

	private String getClientInfo() {
		String path = "";
		
		try {
			SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
			Date currentTime = new Date();
			
			// create the ephemeral znode 
			// "/arcus/client_list/{service_code}/{client hostname}_{ip address}_{pool size}_java_{client version}_{YYYYMMDDHHIISS}_{zk session id}"
			path = ARCUS_BASE_CLIENT_INFO_ZPATH + serviceCode + "/";
			path = path 
				 + InetAddress.getLocalHost().getHostName() + "_"
				 + InetAddress.getLocalHost().getHostAddress() + "_"
				 + this.poolSize + "_java_" + ArcusClient.VERSION + "_"
				 + simpleDateFormat.format(currentTime) + "_" 
				 + zk.getSessionId();
			
		} catch (Exception e) {
			getLogger().fatal("Can't get client info.", e);
			return "";
		}
{'fraction_non_alphanumeric': 0.09603062978590404, 'fraction_numerical': 0.004375683700578215, 'mean_word_length': 4.13809714973906, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3132131', 'n_tokens_mistral': 4358, 'n_tokens_neox': 3757, 'n_words': 1136}