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

net.spy.memcached.ConnectionFactoryBuilder Maven / Gradle / Ivy

There is a newer version: 1.13.2
Show newest version
/*
 * 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;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;

import net.spy.memcached.auth.AuthDescriptor;
import net.spy.memcached.ops.APIType;
import net.spy.memcached.ops.Operation;
import net.spy.memcached.ops.OperationQueueFactory;
import net.spy.memcached.ops.OperationType;
import net.spy.memcached.protocol.ascii.AsciiOperationFactory;
import net.spy.memcached.protocol.binary.BinaryOperationFactory;
import net.spy.memcached.transcoders.Transcoder;

/**
 * Builder for more easily configuring a ConnectionFactory.
 */
public class ConnectionFactoryBuilder {

	private OperationQueueFactory opQueueFactory;
	private OperationQueueFactory readQueueFactory;
	private OperationQueueFactory writeQueueFactory;

	private Transcoder transcoder;
	private Transcoder collectionTranscoder;

	private FailureMode failureMode = FailureMode.Cancel;

	private Collection initialObservers
		= Collections.emptyList();

	private OperationFactory opFact;

	private Locator locator = Locator.ARCUSCONSISTENT;
	private long opTimeout = -1;
	private boolean isDaemon = true;
	private boolean shouldOptimize = false;
	private boolean useNagle = false;
//	private long maxReconnectDelay =
//		DefaultConnectionFactory.DEFAULT_MAX_RECONNECT_DELAY;
	private long maxReconnectDelay = 1;
	
	private int readBufSize = -1;
	private HashAlgorithm hashAlg = HashAlgorithm.KETAMA_HASH;
	private AuthDescriptor authDescriptor = null;
	private long opQueueMaxBlockTime = -1;

//	private int timeoutExceptionThreshold = DefaultConnectionFactory.DEFAULT_MAX_TIMEOUTEXCEPTION_THRESHOLD;
	private int timeoutExceptionThreshold = 10;
	private int timeoutRatioThreshold = DefaultConnectionFactory.DEFAULT_MAX_TIMEOUTRATIO_THRESHOLD;
	
	private int maxFrontCacheElements = DefaultConnectionFactory.DEFAULT_MAX_FRONTCACHE_ELEMENTS;
	private int frontCacheExpireTime = DefaultConnectionFactory.DEFAULT_FRONTCACHE_EXPIRETIME;
	private String frontCacheName = "ArcusFrontCache_" + this.hashCode();
	private boolean frontCacheCopyOnRead = DefaultConnectionFactory.DEFAULT_FRONT_CACHE_COPY_ON_READ;
	private boolean frontCacheCopyOnWrite = DefaultConnectionFactory.DEFAULT_FRONT_CACHE_COPY_ON_WRITE;

	private int bulkServiceThreadCount = DefaultConnectionFactory.DEFAULT_BULKSERVICE_THREAD_COUNT;
	private int bulkServiceLoopLimit = DefaultConnectionFactory.DEFAULT_BULKSERVICE_LOOP_LIMIT;
	private long bulkServiceSingleOpTimeout = DefaultConnectionFactory.DEFAULT_BULKSERVICE_SINGLE_OP_TIMEOUT;
	
	private int maxSMGetChunkSize = DefaultConnectionFactory.DEFAULT_MAX_SMGET_KEY_CHUNK_SIZE;
	
	/* ENABLE_REPLICATION if */
	private boolean arcusReplEnabled = false;

	private ReadPriority readPriority = ReadPriority.MASTER;
	private Map apiReadPriorityList = new HashMap();

	/**
	 * use ARCUS replication
	 * @param enable
	 */
	public ConnectionFactoryBuilder setArcusReplEnabled(boolean enable) {
		arcusReplEnabled = enable;
		return this;
	}

	public boolean getArcusReplEnabled() {
		return arcusReplEnabled;
	}

	/* ENABLE_REPLICATION end */
	/**
	 * Set the operation queue factory.
	 */
	public ConnectionFactoryBuilder setOpQueueFactory(OperationQueueFactory q) {
		opQueueFactory = q;
		return this;
	}

	/**
	 * Set the read queue factory.
	 */
	public ConnectionFactoryBuilder setReadOpQueueFactory(OperationQueueFactory q) {
		readQueueFactory = q;
		return this;
	}

	/**
	 * Set the write queue factory.
	 */
	public ConnectionFactoryBuilder setWriteOpQueueFactory(OperationQueueFactory q) {
		writeQueueFactory = q;
		return this;
	}

	/**
	 * Set the maximum amount of time (in milliseconds) a client is willing to
	 * wait for space to become available in an output queue.
	 */
	public ConnectionFactoryBuilder setOpQueueMaxBlockTime(long t) {
		opQueueMaxBlockTime = t;
		return this;
	}

	/**
	 * Set the default transcoder.
	 */
	public ConnectionFactoryBuilder setTranscoder(Transcoder t) {
		transcoder = t;
		return this;
	}
	
	/**
	 * Set the default collection transcoder.
	 */
	public ConnectionFactoryBuilder setCollectionTranscoder(Transcoder t) {
		collectionTranscoder = t;
		return this;
	}

	/**
	 * Set the failure mode.
	 */
	public ConnectionFactoryBuilder setFailureMode(FailureMode fm) {
		failureMode = fm;
		return this;
	}

	/**
	 * Set the initial connection observers (will observe initial connection).
	 */
	public ConnectionFactoryBuilder setInitialObservers(
			Collection obs) {
		initialObservers = obs;
		return this;
	}

	/**
	 * Set the operation factory.
	 *
	 * Note that the operation factory is used to also imply the type of
	 * nodes to create.
	 *
	 * @see MemcachedNode
	 */
	public ConnectionFactoryBuilder setOpFact(OperationFactory f) {
		opFact = f;
		return this;
	}

	/**
	 * Set the default operation timeout in milliseconds.
	 */
	public ConnectionFactoryBuilder setOpTimeout(long t) {
		opTimeout = t;
		return this;
	}

	/**
	 * Set the daemon state of the IO thread (defaults to true).
	 */
	public ConnectionFactoryBuilder setDaemon(boolean d) {
		isDaemon = d;
		return this;
	}

	/**
	 * Set to false if the default operation optimization is not desirable.
	 */
	public ConnectionFactoryBuilder setShouldOptimize(boolean o) {
		shouldOptimize = o;
		return this;
	}

	/**
	 * Set the read buffer size.
	 */
	public ConnectionFactoryBuilder setReadBufferSize(int to) {
		readBufSize = to;
		return this;
	}

	/**
	 * Set the hash algorithm.
	 */
	public ConnectionFactoryBuilder setHashAlg(HashAlgorithm to) {
		hashAlg = to;
		return this;
	}

	/**
	 * Set to true if you'd like to enable the Nagle algorithm.
	 */
	public ConnectionFactoryBuilder setUseNagleAlgorithm(boolean to) {
		useNagle = to;
		return this;
	}

	/**
	 * Convenience method to specify the protocol to use.
	 */
	public ConnectionFactoryBuilder setProtocol(Protocol prot) {
		switch(prot) {
			case TEXT:
				opFact = new AsciiOperationFactory();
				break;
			case BINARY:
				opFact = new BinaryOperationFactory();
				break;
			default: assert false : "Unhandled protocol: " + prot;
		}
		return this;
	}

	/**
	 * Set the locator type.
	 */
	public ConnectionFactoryBuilder setLocatorType(Locator l) {
		locator = l;
		return this;
	}

	/**
	 * Set the maximum reconnect delay.
	 */
	public ConnectionFactoryBuilder setMaxReconnectDelay(long to) {
		assert to > 0 : "Reconnect delay must be a positive number";
		maxReconnectDelay = to;
		return this;
	}

	/**
	 * Set the auth descriptor to enable authentication on new connections.
	 */
	public ConnectionFactoryBuilder setAuthDescriptor(AuthDescriptor to) {
		authDescriptor = to;
		return this;
	}

	/**
	 * Set the maximum timeout exception threshold
	 */
	public ConnectionFactoryBuilder setTimeoutExceptionThreshold(int to) {
		assert to > 1 : "Minimum timeout exception threshold is 2";
		if (to > 1) {
			timeoutExceptionThreshold = to -2;
		}
		return this;
	}
	
	/**
	 * Set the maximum timeout ratio threshold: 0(disabled, default), 1~99
	 */
	public ConnectionFactoryBuilder setTimeoutRatioThreshold(int to) {
		assert (to >= 0 && to < 100) : "Timeout ratio threshold range is 0~99.";
		if (to < 0 || to >= 100)
			timeoutRatioThreshold = 0; // disable
		else
			timeoutRatioThreshold = to;
		return this;
	}

	/**
	 * Set the maximum number of front cache elements.
	 */
	public ConnectionFactoryBuilder setMaxFrontCacheElements(int to) {
		assert to > 0 : "In case of front cache, the number must be a positive number";
		maxFrontCacheElements = to;
		return this;
	}
	
	/**
	 * Set front cache's expire time.
	 */
	public ConnectionFactoryBuilder setFrontCacheExpireTime(int to) {
		assert to > 0 : "Front cache's expire time must be a positive number";
		frontCacheExpireTime = to;
		return this;
	}
	
	/**
	 * Set front cache copyOnRead property
	 */
	public ConnectionFactoryBuilder setFrontCacheCopyOnRead(boolean copyOnRead) {
		frontCacheCopyOnRead = copyOnRead;
		return this;
	}

	/**
	 * Set front cache copyOnWrite property
	 */
	public ConnectionFactoryBuilder setFrontCacheCopyOnWrite(boolean copyOnWrite) {
		frontCacheCopyOnWrite = copyOnWrite;
		return this;
	}

	/**
	 * Set bulk service default thread count 
	 */
	public ConnectionFactoryBuilder setBulkServiceThreadCount(int to) {
		assert to > 0 : "Bulk service's thread count must be a positive number";
		bulkServiceThreadCount = to;
		return this;
	}
	
	/**
	 * Set bulk service loop limit count 
	 */
	public ConnectionFactoryBuilder setBulkServiceLoopLimit(int to) {
		assert to > 0 : "Bulk service's loop limit must be a positive number";
		bulkServiceLoopLimit = to;
		return this;
	}
	
	/**
	 * Set bulk service each operation timeout 
	 */
	public ConnectionFactoryBuilder setBulkServiceSingleOpTimeout(long to) {
		assert to > 0 : "Bulk service's single operation timeout must be a positive number";
		bulkServiceSingleOpTimeout = to;
		return this;
	}
	
	/**
	 * Set max smget key chunk size
	 */
	public ConnectionFactoryBuilder setMaxSMGetKeyChunkSize(int size) {
		maxSMGetChunkSize = size;
		return this;
	}

	/* ENABLE_REPLICATION if */
	/**
	 * Set read prioirty for choosing replica node to read data
	 */
	public ConnectionFactoryBuilder setReadPriority(ReadPriority priority) {
		readPriority = priority;
		return this;
	}

	public ConnectionFactoryBuilder setAPIReadPriority(APIType apiType, ReadPriority readPriority) {
		OperationType type = apiType.getAPIOpType();
		
		if (type == OperationType.READ || type == OperationType.RW) {
			this.apiReadPriorityList.put(apiType, readPriority);
		}
		
		return this;
	}

	public ConnectionFactoryBuilder setAPIReadPriority(Map apiList) {
		this.apiReadPriorityList.clear();
		
		for (Map.Entry entry : apiList.entrySet()) {
			OperationType type = entry.getKey().getAPIOpType();
			if (type == OperationType.READ || type == OperationType.RW) {
				this.apiReadPriorityList.put(entry.getKey(), entry.getValue());
			}
		}

		return this;
	}
	
	public ConnectionFactoryBuilder clearAPIReadPirority() {
		this.apiReadPriorityList.clear();
		
		return this;
	}
	
	public ReadPriority getAPIReadPriority(APIType apiType) {
		ReadPriority priority = this.apiReadPriorityList.get(apiType);
		
		return priority != null ? priority : ReadPriority.MASTER;
	}
	
	public Map getAPIReadPriority() {
		return this.apiReadPriorityList;
	}

	/* ENABLE_REPLICATION end */
	/**
	 * Get the ConnectionFactory set up with the provided parameters.
	 */
	public ConnectionFactory build() {
		return new DefaultConnectionFactory() {

			/* ENABLE_REPLICATION if */
			@Override
			public MemcachedConnection createConnection(List addrs)
				throws IOException {
				MemcachedConnection c = super.createConnection(addrs);
				c.setArcusReplEnabled(arcusReplEnabled);
				return c;
			}

			/* ENABLE_REPLICATION end */
			@Override
			public BlockingQueue createOperationQueue() {
				return opQueueFactory == null ?
						super.createOperationQueue() : opQueueFactory.create();
			}

			@Override
			public BlockingQueue createReadOperationQueue() {
				return readQueueFactory == null ?
						super.createReadOperationQueue()
						: readQueueFactory.create();
			}

			@Override
			public BlockingQueue createWriteOperationQueue() {
				return writeQueueFactory == null ?
						super.createReadOperationQueue()
						: writeQueueFactory.create();
			}

			@Override
			public NodeLocator createLocator(List nodes) {
				switch(locator) {
					case ARRAY_MOD:
						return new ArrayModNodeLocator(nodes, getHashAlg());
					case CONSISTENT:
						return new KetamaNodeLocator(nodes, getHashAlg());
					case ARCUSCONSISTENT:
						/* ENABLE_REPLICATION if */
						if (arcusReplEnabled) {
							// Arcus repl cluster
							// This locator uses ArcusReplKetamaNodeLocatorConfiguration
							// which builds keys off the server's group name, not
							// its ip:port.
							return new ArcusReplKetamaNodeLocator(nodes, getHashAlg());
						}
						else {
							// Arcus base cluster
							return new ArcusKetamaNodeLocator(nodes, getHashAlg());
						}
						/* ENABLE_REPLICATION else */
						/*
						return new ArcusKetamaNodeLocator(nodes, getHashAlg());
						*/
						/* ENABLE_REPLICATION end */
					default: throw new IllegalStateException(
							"Unhandled locator type: " + locator);
				}
			}

			@Override
			public Transcoder getDefaultTranscoder() {
				return transcoder == null ?
						super.getDefaultTranscoder() : transcoder;
			}
			
			@Override
			public Transcoder getDefaultCollectionTranscoder() {
				return collectionTranscoder == null ?
						super.getDefaultCollectionTranscoder() : collectionTranscoder;
			}

			@Override
			public FailureMode getFailureMode() {
				return failureMode == null ?
						super.getFailureMode() : failureMode;
			}

			@Override
			public HashAlgorithm getHashAlg() {
				return hashAlg == null ? super.getHashAlg() : hashAlg;
			}

			@Override
			public Collection getInitialObservers() {
				return initialObservers;
			}

			@Override
			public OperationFactory getOperationFactory() {
				return opFact == null ? super.getOperationFactory() : opFact;
			}

			@Override
			public long getOperationTimeout() {
				return opTimeout == -1 ?
						super.getOperationTimeout() : opTimeout;
			}

			@Override
			public int getReadBufSize() {
				return readBufSize == -1 ?
						super.getReadBufSize() : readBufSize;
			}

			@Override
			public boolean isDaemon() {
				return isDaemon;
			}

			@Override
			public boolean shouldOptimize() {
				return shouldOptimize;
			}

			@Override
			public boolean useNagleAlgorithm() {
				return useNagle;
			}

			@Override
			public long getMaxReconnectDelay() {
				return maxReconnectDelay;
			}

			@Override
			public AuthDescriptor getAuthDescriptor() {
				return authDescriptor;
			}

			@Override
			public long getOpQueueMaxBlockTime() {
				return opQueueMaxBlockTime > -1 ? opQueueMaxBlockTime
						: super.getOpQueueMaxBlockTime();
			}

			@Override
			public int getTimeoutExceptionThreshold() {
				return timeoutExceptionThreshold;
			}
			
			@Override
			public int getTimeoutRatioThreshold() {
				return timeoutRatioThreshold;
			}

			@Override
			public int getMaxFrontCacheElements() {
				return maxFrontCacheElements;
			}
			
			@Override
			public int getFrontCacheExpireTime() {
				return frontCacheExpireTime;
			}

			@Override
			public String getFrontCacheName() {
				return frontCacheName;
			}

			@Override
			public boolean getFrontCacheCopyOnRead() {
				return frontCacheCopyOnRead;
			}

			@Override
			public boolean getFrontCacheCopyOnWrite() {
				return frontCacheCopyOnWrite;
			}

			@Override
			public int getBulkServiceThreadCount() {
				return bulkServiceThreadCount;
			}
			
			@Override
			public int getBulkServiceLoopLimit() {
				return bulkServiceLoopLimit;
			}
			
			@Override
			public long getBulkServiceSingleOpTimeout() {
				return bulkServiceSingleOpTimeout;
			}
			
			@Override
			public int getDefaultMaxSMGetKeyChunkSize() {
				return maxSMGetChunkSize;
			}
			/* ENABLE_REPLICATION if */

			@Override
			public ReadPriority getReadPriority() {
				return readPriority;
			}
			
			@Override
			public Map getAPIReadPriority() {
				return apiReadPriorityList;
			}
			/* ENABLE_REPLICATION end */
		};
	}

	/**
	 * Type of protocol to use for connections.
	 */
	public static enum Protocol {
		/**
		 * Use the text (ascii) protocol.
		 */
		TEXT,
		/**
		 * Use the binary protocol.
		 */
		BINARY
	}

	/**
	 * Type of node locator to use.
	 */
	public static enum Locator {
		/**
		 * Array modulus - the classic node location algorithm.
		 */
		ARRAY_MOD,
		/**
		 * Fixed Consistent hash algorithm.
		 *
		 * This uses ketema's distribution algorithm, but may be used with any
		 * hash algorithm.
		 */
		CONSISTENT,
		/**
		 * Live Consistent hash algorithm
		 * 
		 * This uses ketama's distribution algorithm, and used with 
		 * node change(add, delete)
		 */
		ARCUSCONSISTENT
	}
}