package ch.usi.da.dmap; /* * Copyright (c) 2017 Università della Svizzera italiana (USI) * * This file is part of URingPaxos. * * URingPaxos is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * URingPaxos is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with URingPaxos. If not, see <http://www.gnu.org/licenses/>. */ import java.io.IOException; import java.util.AbstractSet; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Random; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import org.apache.log4j.Logger; import org.apache.thrift.TException; import org.apache.thrift.protocol.TBinaryProtocol; import org.apache.thrift.protocol.TProtocol; import org.apache.thrift.transport.TSocket; import org.apache.thrift.transport.TTransport; import org.apache.thrift.transport.TTransportException; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.ZooKeeper; import ch.usi.da.dmap.thrift.gen.Command; import ch.usi.da.dmap.thrift.gen.CommandType; import ch.usi.da.dmap.thrift.gen.Dmap; import ch.usi.da.dmap.thrift.gen.MapError; import ch.usi.da.dmap.thrift.gen.Partition; import ch.usi.da.dmap.thrift.gen.RangeCommand; import ch.usi.da.dmap.thrift.gen.RangeResponse; import ch.usi.da.dmap.thrift.gen.RangeType; import ch.usi.da.dmap.thrift.gen.Replica; import ch.usi.da.dmap.thrift.gen.Response; import ch.usi.da.dmap.thrift.gen.WrongPartition; import ch.usi.da.dmap.utils.Pair; import ch.usi.da.dmap.utils.Utils; import ch.usi.da.paxos.lab.DummyWatcher; /** * Name: DistributedOrderedMap<br> * Description: <br> * * Creation date: Jan 28, 2017<br> * $Id$ * * Notes: * - Not using AbstractMap because it implements some methods inefficient for distributed operations. * * * @author Samuel Benz benz@geoid.ch */ public class DistributedOrderedMap<K extends Comparable<K>,V> implements SortedMap<K,V>, Cloneable, java.io.Serializable { private final static long serialVersionUID = -8575201903369745596L; private final static Logger logger = Logger.getLogger(DistributedOrderedMap.class); private final Comparator<? super K> comparator; private final Random rand = new Random(); private ZooKeeper zoo; private final int get_range_size = 500; private long partition_version = 0; private SortedMap<Integer,Set<Replica>> partitions = new TreeMap<Integer,Set<Replica>>(); private Map<Integer,List<Dmap.Client>> clients = new HashMap<Integer,List<Dmap.Client>>(); public final String mapID; public DistributedOrderedMap(String mapID, String zookeeper_host) { this(mapID,zookeeper_host,null); } public DistributedOrderedMap(String mapID, String zookeeper_host, Comparator<? super K> comparator) { this.comparator = comparator; // important at replica this.mapID = mapID; final String path = "/dmap/" + mapID; try { zoo = new ZooKeeper(zookeeper_host,3000,new DummyWatcher()); // lookup one replica to initialize the partitions map List<String> replicas = zoo.getChildren(path,false); if(replicas.isEmpty()){ logger.error(this + " can not locate any replica!"); }else{ int pos = rand.nextInt(replicas.size()); byte[] a = zoo.getData(path + "/" + replicas.get(pos),false,null); String[] as = new String(a).split(";"); String ip = as[0]; int port = Integer.parseInt(as[1]); TTransport transport = new TSocket(ip,port); TProtocol protocol = new TBinaryProtocol(transport); Dmap.Client client = new Dmap.Client(protocol); transport.open(); readPartitions(client); if(!partitions.isEmpty()){ logger.info(this + " initialized."); }else{ logger.error(this + " could not initalze the partition map!"); } } } catch (IOException | KeeperException | InterruptedException e) { logger.error(this + " ZooKeeper init error!",e); } catch (TTransportException e) { logger.error(this + " Thrift init error!",e); } } private Dmap.Client getClient(){ return getClient(null); } private Dmap.Client getClient(Object key){ if(key == null){ // random partition return getClient(rand.nextInt()); }else{ return getClient(key.hashCode()); } } private Dmap.Client getClient(int hash){ Dmap.Client client = null; int partition = 0; SortedMap<Integer,Set<Replica>> tailMap = partitions.tailMap(hash); partition = tailMap.isEmpty() ? partitions.firstKey() : tailMap.firstKey(); if(!clients.containsKey(partition)){ clients.put(partition,new ArrayList<Dmap.Client>()); } List<Dmap.Client> c = clients.get(partition); if(c.isEmpty()){ Set<Replica> replicas = partitions.get(partition); for(Replica r : replicas){ try { client = createClient(r.address); c.add(client); } catch (TTransportException e) { logger.warn(this + " server connection error to " + r.address); } } }else{ int pos = rand.nextInt(c.size()); client = c.get(pos); } return client; } private Dmap.Client createClient(String addr) throws TTransportException{ Dmap.Client client; String[] as = new String(addr).split(";"); String ip = as[0]; int port = Integer.parseInt(as[1]); TSocket socket = new TSocket(ip,port); //socket.getSocket().getTcpNoDelay(); TTransport transport = socket; TProtocol protocol = new TBinaryProtocol(transport); client = new Dmap.Client(protocol); transport.open(); return client; } private void removeClient(Dmap.Client client){ for(Entry<Integer, List<Dmap.Client>> e : clients.entrySet()){ if(e.getValue().contains(client)){ e.getValue().remove(client); logger.warn(this + " server connection error. Remove this client."); if(e.getValue().isEmpty()){ readPartitions(getClient()); } break; } } } private long getCmdID(){ return rand.nextLong(); } private void readPartitions(Dmap.Client client){ try { logger.info(this + " request partition map."); Partition p = client.partition(getCmdID()); if(p.getVersion() != partition_version){ partitions.clear(); partitions.putAll(p.getPartitions()); partition_version = p.getVersion(); logger.info(this + " installed new partition map version " + partition_version + " (" + partitions + ")"); }else{ logger.info(this + " reveived same version partition map."); } } catch (TException e) { logger.error(this,e); } } // single partition commands @Override public V get(Object key) { return get(key,null); } @SuppressWarnings("unchecked") private V get(Object key,Long snapshotID) { if(key == null){ throw new NullPointerException(); } Dmap.Client client = getClient(key); Response ret = null; try { Command cmd = new Command(); cmd.setId(getCmdID()); cmd.setType(CommandType.GET); cmd.setKey(Utils.getBuffer(key)); cmd.setPartition_version(partition_version); if(snapshotID != null){ cmd.setSnapshot(snapshotID); } ret = client.execute(cmd); } catch (MapError e){ logger.error(this + " " + e.errorMsg); } catch (WrongPartition p){ readPartitions(getClient()); return get(key,snapshotID); } catch (TTransportException e){ removeClient(client); return get(key,snapshotID); } catch (TException | IOException e) { logger.error(this,e); } if(ret != null && ret.isSetValue()){ try { return (V) Utils.getObject(ret.getValue()); } catch (ClassNotFoundException | IOException e) { logger.error(this,e); } } return null; } @Override public V put(K key,V value) { return put(key,value,null); } @SuppressWarnings("unchecked") private V put(K key,V value,Long snapshotID) { if(key == null){ throw new NullPointerException(); } Dmap.Client client = getClient(key); Response ret = null; try { Command cmd = new Command(); cmd.setId(getCmdID()); cmd.setType(CommandType.PUT); cmd.setKey(Utils.getBuffer(key)); cmd.setValue(Utils.getBuffer(value)); cmd.setPartition_version(partition_version); if(snapshotID != null){ cmd.setSnapshot(snapshotID); } ret = client.execute(cmd); } catch (MapError e){ logger.error(this + " " + e.errorMsg); } catch (WrongPartition p){ readPartitions(getClient()); return put(key,value,snapshotID); } catch (TTransportException e){ removeClient(client); return put(key,value,snapshotID); } catch (TException | IOException e) { logger.error(this,e); } if(ret != null && ret.isSetValue()){ try { return (V) Utils.getObject(ret.getValue()); } catch (ClassNotFoundException | IOException e) { logger.error(this,e); } } return null; } @Override public V remove(Object key) { return remove(key,null); } @SuppressWarnings("unchecked") private V remove(Object key,Long snapshotID) { if(key == null){ throw new NullPointerException(); } Response ret = null; Dmap.Client client = getClient(key); try { Command cmd = new Command(); cmd.setId(getCmdID()); cmd.setType(CommandType.REMOVE); cmd.setKey(Utils.getBuffer(key)); cmd.setPartition_version(partition_version); if(snapshotID != null){ cmd.setSnapshot(snapshotID); } ret = client.execute(cmd); } catch (MapError e){ logger.error(this + " " + e.errorMsg); } catch (WrongPartition p){ readPartitions(getClient()); return remove(key,snapshotID); } catch (TTransportException e){ removeClient(client); return remove(key,snapshotID); } catch (TException | IOException e) { logger.error(this,e); } if(ret != null && ret.isSetValue()){ try { return (V) Utils.getObject(ret.getValue()); } catch (ClassNotFoundException | IOException e) { logger.error(this,e); } } return null; } @Override public boolean containsKey(Object key) { return containsKey(key,null); } private boolean containsKey(Object key,Long snapshotID) { if(key == null){ throw new NullPointerException(); } V v = get(key,snapshotID); if(v != null){ return true; }else{ return false; } } @Override public void putAll(Map<? extends K, ? extends V> m) { putAll(m,null); } private void putAll(Map<? extends K, ? extends V> m,Long snapshotID) { for(Map.Entry<? extends K, ? extends V> e : m.entrySet()){ put(e.getKey(),e.getValue(),snapshotID); } } // multi-partition commands private long sizeLong(Long snapshotID) { Response ret = null; Dmap.Client client = getClient(); try { Command cmd = new Command(); cmd.setId(getCmdID()); cmd.setType(CommandType.SIZE); cmd.setPartition_version(partition_version); if(snapshotID != null){ cmd.setSnapshot(snapshotID); } ret = client.execute(cmd); } catch (MapError e){ logger.error(this + " " + e.errorMsg); } catch (WrongPartition p){ readPartitions(getClient()); return sizeLong(snapshotID); } catch (TTransportException e){ removeClient(client); return sizeLong(snapshotID); } catch (TException e) { logger.error(this,e); } if(ret != null && ret.isSetCount()){ return ret.getCount(); } return 0; } @Override public int size() { return (int) sizeLong(null); } @Override public boolean isEmpty() { return size() == 0; } @Override public boolean containsValue(Object value) { return containsValue(value,null); } private boolean containsValue(Object value,Long snapshotID) { if(value == null){ throw new NullPointerException(); } Response ret = null; Dmap.Client client = getClient(); try { Command cmd = new Command(); cmd.setId(getCmdID()); cmd.setType(CommandType.CONTAINSVALUE); cmd.setValue(Utils.getBuffer(value)); cmd.setPartition_version(partition_version); if(snapshotID != null){ cmd.setSnapshot(snapshotID); } ret = client.execute(cmd); } catch (MapError e){ logger.error(this + " " + e.errorMsg); } catch (WrongPartition p){ readPartitions(getClient()); return containsValue(value,snapshotID); } catch (TTransportException e){ removeClient(client); return containsValue(value,snapshotID); } catch (TException | IOException e) { logger.error(this,e); } if(ret != null && ret.getCount() > 0){ return true; } return false; } @Override public void clear() { clear(null); } private void clear(Long snapshotID){ Dmap.Client client = getClient(); try { Command cmd = new Command(); cmd.setId(getCmdID()); cmd.setType(CommandType.CLEAR); cmd.setPartition_version(partition_version); if(snapshotID != null){ cmd.setSnapshot(snapshotID); } client.execute(cmd); } catch (MapError e){ logger.error(this + " " + e.errorMsg); } catch (WrongPartition p){ readPartitions(getClient()); clear(snapshotID); } catch (TTransportException e){ removeClient(client); clear(snapshotID); } catch (TException e) { logger.error(this,e); } } @Override public K firstKey() { return firstKey(null); } @SuppressWarnings("unchecked") private K firstKey(Long snapshotID){ Dmap.Client client = getClient(); Response ret = null; try { Command cmd = new Command(); cmd.setId(getCmdID()); cmd.setType(CommandType.FIRSTKEY); cmd.setPartition_version(partition_version); if(snapshotID != null){ cmd.setSnapshot(snapshotID); } ret = client.execute(cmd); } catch (MapError e){ logger.error(this + " " + e.errorMsg); } catch (WrongPartition p){ readPartitions(getClient()); return firstKey(snapshotID); } catch (TTransportException e){ removeClient(client); return firstKey(snapshotID); } catch (TException e) { logger.error(this,e); } if(ret != null && ret.isSetKey()){ try { return (K) Utils.getObject(ret.getKey()); } catch (ClassNotFoundException | IOException e) { logger.error(this,e); } } throw new NoSuchElementException(); } @Override public K lastKey() { return lastKey(null); } @SuppressWarnings("unchecked") private K lastKey(Long snapshotID){ Response ret = null; Dmap.Client client = getClient(); try { Command cmd = new Command(); cmd.setId(getCmdID()); cmd.setType(CommandType.LASTKEY); cmd.setPartition_version(partition_version); if(snapshotID != null){ cmd.setSnapshot(snapshotID); } ret = client.execute(cmd); } catch (MapError e){ logger.error(this + " " + e.errorMsg); } catch (WrongPartition p){ readPartitions(getClient()); return lastKey(snapshotID); } catch (TTransportException e){ removeClient(client); return lastKey(snapshotID); } catch (TException e) { logger.error(this,e); } if(ret != null && ret.isSetKey()){ try { return (K) Utils.getObject(ret.getKey()); } catch (ClassNotFoundException | IOException e) { logger.error(this,e); } } throw new NoSuchElementException(); } // global snapshot/iterator commands private SortedMap<K,V> subMap(K fromKey,K toKey,Long snapshotID) { RangeResponse ret = null; SortedMap<K,V> submap = null; Dmap.Client client = getClient(); try { RangeCommand cmd = new RangeCommand(); cmd.setId(getCmdID()); cmd.setType(RangeType.CREATERANGE); cmd.setPartition_version(partition_version); if(fromKey != null){ cmd.setFromkey(Utils.getBuffer(fromKey)); } if(toKey != null){ cmd.setTokey(Utils.getBuffer(toKey)); } if(snapshotID != null){ // snapshot of a snapshot? cmd.setSnapshot(snapshotID); } ret = client.range(cmd); if(ret.isSetSnapshot()){ snapshotID = ret.getSnapshot(); Map<Integer,Long> partitions_size = new HashMap<Integer,Long>(); for(Entry<Integer,Set<Replica>> e : partitions.entrySet()){ // get size of every partition slice RangeResponse r = null; while(r == null){ RangeCommand s = new RangeCommand(); s.setId(getCmdID()); s.setType(RangeType.PARTITIONSIZE); s.setPartition_version(partition_version); s.setSnapshot(snapshotID); try{ r = getClient(e.getKey()).range(s); }catch(MapError | TTransportException me){ // retry snapshot must exist eventually Thread.sleep(50); } } partitions_size.put(e.getKey(),r.getCount()); } submap = new SnapshotView(snapshotID,partitions_size); logger.debug(this + " created snapshot view " + snapshotID); } } catch (MapError e){ logger.error(this + " " + e.errorMsg); } catch (WrongPartition p){ readPartitions(getClient()); return subMap(fromKey,toKey,snapshotID); } catch (TTransportException e){ removeClient(client); return subMap(fromKey,toKey,snapshotID); } catch (TException | IOException | InterruptedException e) { logger.error(this,e); } return submap; } public void removeSnapshot(Long snapshotID){ RangeCommand cmd = new RangeCommand(); Dmap.Client client = getClient(); cmd.setId(getCmdID()); cmd.setType(RangeType.DELETERANGE); cmd.setSnapshot(snapshotID); cmd.setPartition_version(partition_version); try { client.range(cmd); logger.debug(this + " released snapshot " + snapshotID); } catch (MapError e) { logger.error(this + " error!",e); } catch (WrongPartition p){ readPartitions(getClient()); removeSnapshot(snapshotID); } catch (TTransportException e){ removeClient(client); removeSnapshot(snapshotID); } catch (TException e) { logger.error(this + " error!",e); } } @Override public SortedMap<K,V> subMap(K fromKey, K toKey) { return subMap(fromKey,toKey,null); } @Override public SortedMap<K,V> headMap(K toKey) { return subMap(null,toKey,null); } @Override public SortedMap<K,V> tailMap(K fromKey) { return subMap(fromKey,null,null); } @Override public Set<K> keySet() { return subMap(null,null,null).keySet(); } @Override public Collection<V> values() { return subMap(null,null,null).values(); } @Override public Set<java.util.Map.Entry<K,V>> entrySet() { return subMap(null,null,null).entrySet(); } // others @Override public Comparator<? super K> comparator() { return comparator; } @Override public String toString(){ return "Distributed Ordered Map: " + mapID; } @Override public boolean equals(Object obj) { if(obj instanceof DistributedOrderedMap<?,?>){ if(this.mapID.equals(((DistributedOrderedMap<?,?>) obj).mapID)){ return true; } } return false; } @Override public int hashCode() { return mapID.hashCode(); } // view and iterators on a snapshot class SnapshotView implements SortedMap<K,V> { public final Map<Integer,Long> partitions_size; public final long snapshotID; public final long size; public volatile boolean closed = false; public SnapshotView(long snapshotID, Map<Integer,Long> partitions_size){ this.partitions_size = partitions_size; this.snapshotID = snapshotID; long size = 0; for(Long l : partitions_size.values()){ size += l; } this.size = size; } @Override public int size() { return (int) size; } @Override public boolean isEmpty() { return size > 0 ? false : true; } @Override public boolean containsKey(Object key) { return DistributedOrderedMap.this.containsKey(key,snapshotID); } @Override public boolean containsValue(Object value) { return DistributedOrderedMap.this.containsValue(value,snapshotID); } @Override public V get(Object key) { return DistributedOrderedMap.this.get(key,snapshotID); } @Override public V put(K key,V value) { throw new IllegalArgumentException(); //return DistributedOrderedMap.this.put(key,value,snapshotID); } @Override public V remove(Object key) { throw new IllegalArgumentException(); //return DistributedOrderedMap.this.remove(key,snapshotID); } @Override public void putAll(Map<? extends K, ? extends V> m) { throw new IllegalArgumentException(); //DistributedOrderedMap.this.putAll(m,snapshotID); } @Override public void clear() { removeSnapshot(); //DistributedOrderedMap.this.clear(snapshotID); } public void removeSnapshot(){ closed = true; DistributedOrderedMap.this.removeSnapshot(snapshotID); } @Override public Comparator<? super K> comparator() { return DistributedOrderedMap.this.comparator(); } @Override public SortedMap<K, V> subMap(K fromKey,K toKey) { return DistributedOrderedMap.this.subMap(fromKey,toKey,snapshotID); } @Override public SortedMap<K, V> headMap(K toKey) { return DistributedOrderedMap.this.subMap(null,toKey,snapshotID); } @Override public SortedMap<K, V> tailMap(K fromKey) { return DistributedOrderedMap.this.subMap(fromKey,null,snapshotID); } @Override public K firstKey() { return DistributedOrderedMap.this.firstKey(snapshotID); } @Override public K lastKey() { return DistributedOrderedMap.this.lastKey(snapshotID); } @Override public Set<K> keySet() { //TODO: return null; } @Override public Collection<V> values() { //TODO: return null; } @Override public Set<java.util.Map.Entry<K,V>> entrySet() { return new EntrySet(this); } @Override public String toString(){ return DistributedOrderedMap.this + " snapshot: " + snapshotID + " size: " + size; } } class EntrySet extends AbstractSet<Map.Entry<K,V>> { private final SnapshotView view; private final BlockingQueue<Map.Entry<K,V>> queue[]; private final Thread threads[]; private final long queue_size[]; @SuppressWarnings("unchecked") public EntrySet(SnapshotView view){ this.view = view; queue = (BlockingQueue<Map.Entry<K,V>>[]) new BlockingQueue[view.partitions_size.size()]; queue_size = new long[view.partitions_size.size()]; threads = new Thread[view.partitions_size.size()]; int i = 0; for(Entry<Integer,Long> e : view.partitions_size.entrySet()){ queue[i] = new LinkedBlockingQueue<Map.Entry<K,V>>(get_range_size); queue_size[i] = e.getValue(); if(queue_size[i] > 0){ threads[i] = new Thread(new QueueFiller(view,queue[i],e)); threads[i].start(); } i++; } } public Iterator<Map.Entry<K,V>> iterator() { return new EntryIterator<Map.Entry<K,V>>(this,queue,queue_size); } public boolean contains(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry<?,?> entry = (Map.Entry<?,?>) o; Object value = entry.getValue(); V p = view.get(entry.getKey()); return p != null && p.equals(value); } public boolean remove(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry<?,?> entry = (Map.Entry<?,?>) o; Object value = entry.getValue(); V p = view.get(entry.getKey()); if (p != null && p.equals(value)) { view.remove(entry.getKey()); return true; } return false; } public int size() { return view.size(); } public void clear() { view.clear(); for(Thread t : threads){ if(t != null){ t.interrupt(); } } } } class EntryIterator<T> implements Iterator<T> { private final EntrySet set; private long delivered = 0; private final BlockingQueue<T> queue[]; private final long queue_delivered[]; private final long queue_size[]; T last = null; EntryIterator(EntrySet set, BlockingQueue<T> queue[], long[] queue_size) { this.set = set; this.queue = queue; this.queue_size = queue_size; queue_delivered = new long[queue.length]; } public final boolean hasNext() { return delivered < set.view.size ? true : false; } public void remove() { if(last == null){ throw new IllegalStateException(); } set.remove(last); } @SuppressWarnings("unchecked") @Override public T next() { T o = null; int qi = 0; if(delivered < set.view.size){ for(int i=0;i<queue.length;i++){ if(queue_delivered[i] < queue_size[i]){ T s = null; while(s == null){ s = queue[i].peek(); if(s == null){ try { Thread.sleep(100); } catch (InterruptedException e) { } } } if(o == null || ((Map.Entry<K,V>) s).getKey().compareTo(((Map.Entry<K,V>)o).getKey()) < 0){ o = s; qi = i; } } } delivered++; queue_delivered[qi]++; return queue[qi].poll(); }else{ throw new NoSuchElementException(); } } } class QueueFiller implements Runnable { private final SnapshotView view; private final BlockingQueue<Map.Entry<K,V>> queue; private final Map.Entry<Integer,Long> partitions_size; public QueueFiller(SnapshotView view,BlockingQueue<Map.Entry<K,V>> queue,Map.Entry<Integer,Long> partitions_size){ this.view = view; this.queue = queue; this.partitions_size = partitions_size; } @Override public void run() { long snapshotID = view.snapshotID; long size = partitions_size.getValue(); Set<Replica> replicas = partitions.get(partitions_size.getKey()); Dmap.Client client = null; while(client == null){ try { Replica replica = (Replica)replicas.toArray()[rand.nextInt(replicas.size())]; client = createClient(replica.address); } catch (TTransportException e1) { } } long retreived = 0; int from = 0; do{ try { RangeCommand cmd = new RangeCommand(); cmd.setId(getCmdID()); cmd.setType(RangeType.GETRANGE); cmd.setSnapshot(snapshotID); cmd.setFromid(from); cmd.setToid(from+get_range_size); cmd.setPartition_version(partition_version); from = from+get_range_size; if(client == null){ throw new TTransportException(); } RangeResponse ret = client.range(cmd); //Idea: ask multiple replicas with different offset if(ret != null){ if(ret.isSetValues()){ @SuppressWarnings("unchecked") List<Pair<K,V>> sublist = (List<Pair<K,V>>) Utils.getObject(ret.getValues()); for(Pair<K,V> e : sublist){ queue.put(e); retreived++; } } } } catch (MapError e){ /*if(!view.closed){ logger.error(view + " error!",e); }*/ } catch (WrongPartition p){ } catch (TTransportException e){ removeClient(client); try { Replica replica = (Replica)replicas.toArray()[rand.nextInt(replicas.size())]; client = createClient(replica.address); } catch (TTransportException e1) { } } catch (TException | ClassNotFoundException | IOException e) { logger.error(view + " error!",e); } catch (InterruptedException e){ logger.debug(view + " queue filler interrupted."); Thread.currentThread().interrupt(); break; } }while(retreived < size || view.closed); logger.debug(view + " queue filler stopped."); client.getInputProtocol().getTransport().close(); client.getOutputProtocol().getTransport().close(); } } }