/*
* 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.google.common.util.concurrent.ThreadFactoryBuilder;
import com.lmax.disruptor.EventHandler;
import com.lmax.disruptor.ExceptionHandler;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.dsl.Disruptor;
import com.tuplejump.stargate.cassandra.RowIndexSupport;
import org.apache.cassandra.db.ColumnFamily;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicLong;
/**
* User: satya
*/
public class IndexingService {
protected static final Logger logger = LoggerFactory.getLogger(Stargate.class);
ExecutorService executorService;
Map<String, RowIndexSupport> support;
IndexEntryEvent.Factory eventFactory = new IndexEntryEvent.Factory();
int numWorkers = Math.max(4, Runtime.getRuntime().availableProcessors());
// Specify the size of the ring buffer, must be power of 2.
int bufferSize = 128 * numWorkers;
Disruptor<IndexEntryEvent> disruptor;
RingBuffer<IndexEntryEvent> ringBuffer;
AtomicLong reads;
AtomicLong writes;
public IndexingService(AtomicLong reads, AtomicLong writes) {
support = new HashMap<>();
this.reads = reads;
this.writes = writes;
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
.setNameFormat("SGRingBuffer-Thread-%d").build();
executorService = Executors.newFixedThreadPool(numWorkers, namedThreadFactory);
disruptor = new Disruptor<>(eventFactory, bufferSize, executorService);
ringBuffer = disruptor.getRingBuffer();
ExceptionHandler exceptionHandler = new FatalExceptionHandler();
disruptor.handleExceptionsWith(exceptionHandler);
EventHandler<IndexEntryEvent>[] eventHandlers = new EventHandler[numWorkers];
for (int i = 0; i < numWorkers; i++) {
eventHandlers[i] = new IndexEventHandler(this, i, numWorkers);
}
disruptor.handleEventsWith(eventHandlers);
disruptor.start();
}
public void register(RowIndexSupport rowIndexSupport) {
this.support.put(rowIndexSupport.tableMapper.cfMetaData.cfName, rowIndexSupport);
}
public void index(ByteBuffer rowkeyBuffer, ColumnFamily columnFamily) {
long sequence = ringBuffer.next();
try {
// Get the entry in the Disruptor
// for the sequence
IndexEntryEvent event = ringBuffer.get(sequence);
event.setData(rowkeyBuffer, columnFamily);
} finally {
ringBuffer.publish(sequence);
}
}
public void updateAllIndexers() {
for (RowIndexSupport rowIndexSupport : support.values()) {
updateIndexers(rowIndexSupport);
}
}
public void updateIndexers(RowIndexSupport rowIndexSupport) {
if (rowIndexSupport.indexContainer instanceof MonolithIndexContainer) {
rowIndexSupport.indexContainer.updateIndexers(null);
} else {
throw new RuntimeException("VNodeIndexContainer is a WIP and has been disabled.");
// if (StorageService.instance.isInitialized()) {
// Collection<Range<Token>> ranges = StorageService.instance.getLocalRanges(rowIndexSupport.keyspace);
// rowIndexSupport.indexContainer.updateIndexers(ranges);
// }
}
}
private class FatalExceptionHandler implements ExceptionHandler {
@Override
public void handleEventException(final Throwable ex, final long sequence, final Object event) {
logger.error("Exception processing: " + sequence + " " + event, ex);
throw new RuntimeException(ex);
}
@Override
public void handleOnStartException(final Throwable ex) {
logger.error("Exception during onStart()", ex);
}
@Override
public void handleOnShutdownException(final Throwable ex) {
logger.error("Exception during onShutdown()", ex);
}
}
}