package org.apache.blur.manager.indexserver; import java.io.Closeable; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import org.apache.blur.log.Log; import org.apache.blur.log.LogFactory; import org.apache.blur.thrift.generated.ShardState; /** * 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. */ /** * This class holds the current state of any given shard within the shard * server. * */ public class ShardStateManager implements Closeable { private static final Log LOG = LogFactory.getLog(ShardStateManager.class); private static final long _5_SECONDS = TimeUnit.SECONDS.toMillis(5); private static final long _60_SECONDS = TimeUnit.SECONDS.toMillis(60); private final Map<Key, Value> stateMap = new ConcurrentHashMap<Key, Value>(); private final Timer timer; public ShardStateManager() { timer = new Timer("ShardStateManager-cleanup", true); timer.schedule(new TimerTask() { @Override public void run() { try { cleanup(); } catch (Throwable t) { LOG.error("Unkown error whiel trying to cleanup shard state manager.", t); } } private void cleanup() { Collection<Key> toBeDeleted = null; for (Entry<Key, Value> e : stateMap.entrySet()) { if (shouldBeRemoved(e)) { if (toBeDeleted == null) { toBeDeleted = new HashSet<ShardStateManager.Key>(); } toBeDeleted.add(e.getKey()); } } if (toBeDeleted != null) { for (Key k : toBeDeleted) { stateMap.remove(k); } } } private boolean shouldBeRemoved(Entry<Key, Value> e) { if (e.getValue().timeToBeRemoved < System.currentTimeMillis()) { return true; } return false; } }, _5_SECONDS, _5_SECONDS); } public void opening(String table, String shard) { setState(table, shard, ShardState.OPENING); } public void open(String table, String shard) { setState(table, shard, ShardState.OPEN); } public void openingError(String table, String shard) { setState(table, shard, ShardState.OPENING_ERROR); } public void closing(String table, String shard) { setState(table, shard, ShardState.CLOSING); } public void closed(String table, String shard) { setState(table, shard, ShardState.CLOSED); } public void closingError(String table, String shard) { setState(table, shard, ShardState.CLOSING_ERROR); } public Map<String, ShardState> getShardState(String table) { Map<String, ShardState> result = new HashMap<String, ShardState>(); List<Entry<Key, Value>> entryList = new ArrayList<Entry<Key, Value>>(stateMap.entrySet()); for (Entry<Key, Value> entry : entryList) { Key key = entry.getKey(); if (key.table.equals(table)) { result.put(key.shard, entry.getValue().shardState); } } return result; } private void setState(String table, String shard, ShardState state) { switch (state) { case CLOSED: case CLOSING_ERROR: stateMap.put(new Key(table, shard), new Value(state, System.currentTimeMillis() + _60_SECONDS)); return; default: stateMap.put(new Key(table, shard), new Value(state)); return; } } private static class Value { final ShardState shardState; final long timeToBeRemoved; Value(ShardState shardState) { this(shardState, Long.MAX_VALUE); } Value(ShardState shardState, long timeToBeRemoved) { this.shardState = shardState; this.timeToBeRemoved = timeToBeRemoved; } } private static class Key { final String table; final String shard; Key(String table, String shard) { this.table = table; this.shard = shard; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((shard == null) ? 0 : shard.hashCode()); result = prime * result + ((table == null) ? 0 : table.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Key other = (Key) obj; if (shard == null) { if (other.shard != null) return false; } else if (!shard.equals(other.shard)) return false; if (table == null) { if (other.table != null) return false; } else if (!table.equals(other.table)) return false; return true; } } @Override public void close() { timer.cancel(); timer.purge(); } }