def __init__(self, hosts, timeout): self.hosts = [ (server, instance) for (server, port, instance) in hosts ] self.ports = dict( ((server, instance), port) for (server, port, instance) in hosts ) self.timeout = float(timeout) self.hash_ring = ConsistentHashRing(self.hosts) self.connections = {} self.last_failure = {} # Create a connection pool for each host for host in self.hosts: self.connections[host] = set()
class CarbonLinkPool: def __init__(self, hosts, timeout): self.hosts = [ (server, instance) for (server, port, instance) in hosts ] self.ports = dict( ((server, instance), port) for (server, port, instance) in hosts ) self.timeout = float(timeout) self.hash_ring = ConsistentHashRing(self.hosts) self.connections = {} self.last_failure = {} # Create a connection pool for each host for host in self.hosts: self.connections[host] = set() def select_host(self, metric): "Returns the carbon host that has data for the given metric" return self.hash_ring.get_node(metric) def get_connection(self, host): # First try to take one out of the pool for this host (server, instance) = host port = self.ports[host] connectionPool = self.connections[host] try: return connectionPool.pop() except KeyError: pass #nothing left in the pool, gotta make a new connection log.cache("CarbonLink creating a new socket for %s" % str(host)) connection = socket.socket() connection.settimeout(self.timeout) try: connection.connect( (server, port) ) except: self.last_failure[host] = time.time() raise else: connection.setsockopt( socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1 ) return connection def query(self, metric): request = dict(type='cache-query', metric=metric) results = self.send_request(request) log.cache("CarbonLink cache-query request for %s returned %d datapoints" % (metric, len(results))) return results['datapoints'] def get_metadata(self, metric, key): request = dict(type='get-metadata', metric=metric, key=key) results = self.send_request(request) log.cache("CarbonLink get-metadata request received for %s:%s" % (metric, key)) return results['value'] def set_metadata(self, metric, key, value): request = dict(type='set-metadata', metric=metric, key=key, value=value) results = self.send_request(request) log.cache("CarbonLink set-metadata request received for %s:%s" % (metric, key)) return results def send_request(self, request): metric = request['metric'] serialized_request = pickle.dumps(request, protocol=-1) len_prefix = struct.pack("!L", len(serialized_request)) request_packet = len_prefix + serialized_request host = self.select_host(metric) conn = self.get_connection(host) try: conn.sendall(request_packet) result = self.recv_response(conn) except: self.last_failure[host] = time.time() raise else: self.connections[host].add(conn) if 'error' in result: raise CarbonLinkRequestError(result['error']) else: return result def recv_response(self, conn): len_prefix = recv_exactly(conn, 4) body_size = struct.unpack("!L", len_prefix)[0] body = recv_exactly(conn, body_size) return unpickle.loads(body)