/* * Copyright 2014, Tuplejump Inc. * * 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 com.tuplejump.stargate; import com.tuplejump.stargate.cassandra.RowIndexSupport; import org.apache.cassandra.db.ColumnFamily; import org.apache.cassandra.dht.Range; import org.apache.cassandra.dht.Token; import org.apache.cassandra.gms.*; import org.apache.cassandra.service.StorageService; import org.apache.cassandra.utils.FBUtilities; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.management.MBeanServer; import javax.management.ObjectName; import java.io.IOException; import java.lang.management.ManagementFactory; import java.net.InetAddress; import java.nio.ByteBuffer; import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicLong; /** * User: satya */ public class Stargate implements IEndpointStateChangeSubscriber, StargateMBean { protected static final Logger logger = LoggerFactory.getLogger(Stargate.class); private final static Stargate INSTANCE = new Stargate(); static { MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); try { mbs.registerMBean(INSTANCE, new ObjectName(MBEAN_NAME)); } catch (Exception e) { throw new RuntimeException(e); } } public static final String COMMIT_LOGS = "commit-logs"; public static Exception constructionException; IndexingService indexingService; private Stargate() { try { indexingService = new IndexingService(getAtomicLong(COMMIT_LOGS + "reads"), getAtomicLong(COMMIT_LOGS + "writes")); Gossiper.instance.register(this); } catch (Exception e) { constructionException = e; } } public AtomicLong getAtomicLong(String name) { return new AtomicLong(); } public static Stargate getInstance() { if (constructionException != null) throw new RuntimeException(constructionException); return INSTANCE; } public void register(RowIndexSupport rowIndexSupport) { this.indexingService.register(rowIndexSupport); indexingService.updateIndexers(rowIndexSupport); } public long index(ByteBuffer rowKey, ColumnFamily columnFamily) { final RowIndexSupport rowIndexSupport = indexingService.support.get(columnFamily.metadata().cfName); try { rowIndexSupport.indexRow(rowKey, columnFamily); } catch (Exception e) { logger.error("Error occurred while indexing row of [" + columnFamily.metadata().cfName + "]", e); } finally { indexingService.reads.incrementAndGet(); } long writeGen = indexingService.writes.incrementAndGet(); if (logger.isDebugEnabled()) logger.debug("Write gen:" + writeGen); return writeGen; } public long publish(ByteBuffer rowKey, ColumnFamily columnFamily) { indexingService.index(rowKey, columnFamily); long writeGen = indexingService.writes.incrementAndGet(); if (logger.isDebugEnabled()) logger.debug("Write gen:" + writeGen); return writeGen; } public void catchUp(long latest) { while (true) { if (indexingService.reads.get() >= latest) break; } } @Override public void onJoin(InetAddress endpoint, EndpointState epState) { } @Override public void beforeChange(InetAddress endpoint, EndpointState currentState, ApplicationState newStateKey, VersionedValue newValue) { } @Override public void onChange(InetAddress endpoint, ApplicationState state, VersionedValue value) { if (state == ApplicationState.TOKENS && FBUtilities.getBroadcastAddress().equals(endpoint)) { indexingService.updateAllIndexers(); } } @Override public void onAlive(InetAddress endpoint, EndpointState state) { } @Override public void onDead(InetAddress endpoint, EndpointState state) { } @Override public void onRemove(InetAddress endpoint) { } @Override public void onRestart(InetAddress endpoint, EndpointState state) { } @Override public String[] allIndexes() { String[] allIndexes = new String[indexingService.support.size()]; int i = 0; for (Map.Entry<String, RowIndexSupport> entry : indexingService.support.entrySet()) { RowIndexSupport rowIndexSupport = entry.getValue(); allIndexes[i++] = rowIndexSupport.indexContainer.indexName(); } return allIndexes; } @Override public String[] indexShards(String indexName) { RowIndexSupport indexSupport = getRowIndexSupportByIndexName(indexName); if (indexSupport != null && indexSupport.indexContainer instanceof PerVNodeIndexContainer) { PerVNodeIndexContainer indexContainer = (PerVNodeIndexContainer) indexSupport.indexContainer; Set<Range<Token>> indexShards = indexContainer.indexers.keySet(); String[] indexRanges = new String[indexShards.size()]; int i = 0; for (Range<Token> indexRange : indexShards) { indexRanges[i++] = indexRange.toString(); } return indexRanges; } return new String[]{""}; } @Override public String describeIndex(String indexName) throws IOException { RowIndexSupport indexSupport = getRowIndexSupportByIndexName(indexName); if (indexSupport != null) { return indexSupport.getOptions().describeAsJson(); } return null; } private RowIndexSupport getRowIndexSupportByIndexName(String indexName) { for (Map.Entry<String, RowIndexSupport> entry : indexingService.support.entrySet()) { RowIndexSupport rowIndexSupport = entry.getValue(); if (rowIndexSupport.indexContainer.indexName().equalsIgnoreCase(indexName)) return rowIndexSupport; } return null; } @Override public long indexLiveSize(String indexName) { RowIndexSupport indexSupport = getRowIndexSupportByIndexName(indexName); if (indexSupport != null) { return indexSupport.indexContainer.liveSize(); } return 0; } @Override public long indexSize(String indexName) { RowIndexSupport indexSupport = getRowIndexSupportByIndexName(indexName); if (indexSupport != null) { return indexSupport.indexContainer.size(); } return 0; } @Override public long writeGeneration() { return indexingService.writes.get(); } @Override public long readGeneration() { return indexingService.reads.get(); } }