/*
* Copyright (c) 2011 LinkedIn, 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.flaptor.indextank.rpc;
import java.io.IOException;
import java.util.Map;
import org.apache.log4j.Logger;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TBinaryProtocol.Factory;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TThreadPoolServer;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TTransportException;
import com.flaptor.indextank.BoostingIndexer;
import com.flaptor.indextank.index.IndexEngine;
import com.flaptor.util.Execute;
public class IndexerServer {
private static final Logger logger = Logger.getLogger(Execute.whoAmI());
private IndexEngine ie;
private BoostingIndexer indexer;
private int port;
public IndexerServer(IndexEngine ie, com.flaptor.indextank.BoostingIndexer indexer, int port) {
this.ie = ie;
this.indexer = indexer;
this.port = port;
}
public void start(){
Thread t = new Thread() {
public void run() {
try {
TServerSocket serverTransport = new TServerSocket(IndexerServer.this.port);
Indexer.Processor processor = new Indexer.Processor(new IndexerImpl(ie, IndexerServer.this.indexer));
Factory protFactory = new TBinaryProtocol.Factory(true, true);
TServer server = new TThreadPoolServer(processor, serverTransport, protFactory);
System.out.println("Starting indexer server on port " + IndexerServer.this.port + " ...");
server.serve();
} catch( TTransportException tte ){
tte.printStackTrace();
}
}
} ;
t.start();
}
/**
* Converts a Thrift Document into a Indextank Document.
*/
private static com.flaptor.indextank.index.Document toIndexTankDocument(Document doc) {
return new com.flaptor.indextank.index.Document(doc.get_fields());
}
private class IndexerImpl implements Indexer.Iface {
private IndexEngine ie;
private BoostingIndexer indexer;
// constructor
private IndexerImpl(IndexEngine ie, BoostingIndexer indexer){
this.ie = ie;
this.indexer = indexer;
}
@Override
public void promoteResult(String docId, String query) throws IndextankException {
try {
logger.info("Promoting " + docId + " for query: " + query);
this.indexer.promoteResult(docId, query);
} catch (RuntimeException e) {
logger.error("RuntimeException while processing promoteResult.", e);
throw new IndextankException(e.getMessage());
}
}
@Override
public void updateCategories(String docId, Map<String, String> categories) throws IndextankException {
try {
logger.info("Updating " + categories.size() + " categories for " + docId);
this.indexer.updateCategories(docId, categories);
} catch (RuntimeException e) {
logger.error("RuntimeException while processing updateCategories.", e);
throw new IndextankException(e.getMessage());
}
}
@Override
public void dump() throws IndextankException {
try {
logger.info("Executing dump");
this.indexer.dump();
} catch (IOException e) {
logger.error("IOException while processing dump.", e);
throw new IndextankException(e.getMessage());
} catch (RuntimeException e) {
logger.error("RuntimeException while processing dump.", e);
throw new IndextankException(e.getMessage());
}
}
@Override
public void delDoc(String docId) throws IndextankException {
try {
logger.info("Deleting document " + docId);
this.indexer.del(docId);
} catch (RuntimeException e) {
logger.error("RuntimeException while processing delDoc.", e);
throw new IndextankException(e.getMessage());
}
}
@Override
public IndexerStats stats() throws IndextankException {
try {
return new IndexerStats();
} catch (RuntimeException e) {
logger.error("RuntimeException while processing stats.", e);
throw new IndextankException(e.getMessage());
}
}
@Override
public IndexerStatus getStatus() {
IndexerStatus status = ie.getStatus();
logger.info("Returning index status (" + status.ordinal() + ") : " + status);
return status;
}
@Override
public void ping() throws TException {
logger.info("Pinged");
}
@Override
public void startFullRecovery() {
logger.info("Starting full recovery");
ie.startFullRecovery();
}
@Override
public void addDoc(String docId, Document doc, int timestampBoost, Map<Integer, Double> boosts) throws IndextankException, TException {
try {
logger.info("Adding document " + docId + " for timestamp " + timestampBoost + " with " + doc.get_fields_size() + " fields and " + boosts.size() + " variables.");
if (null == docId || docId.isEmpty()) {
String msg = "Received invalid documentId: \"" + docId + "\". Skipping Add.";
logger.error(msg);
throw new IndextankException(msg);
}
this.indexer.add(docId, IndexerServer.toIndexTankDocument(doc), timestampBoost, boosts);
} catch (RuntimeException e) {
logger.error("RuntimeException while processing addDoc.", e);
throw new IndextankException(e.getMessage());
}
}
@Override
public void updateBoost(String docId, Map<Integer, Double> boosts) throws IndextankException, TException {
try {
logger.info("Updating " + boosts.size() + " variables for document " + docId);
this.indexer.updateBoosts(docId, boosts);
} catch (RuntimeException e) {
logger.error("RuntimeException while processing updateBoost.", e);
throw new IndextankException(e.getMessage());
}
}
@Override
public void updateTimestampBoost(String docId, int timestampBoost) throws IndextankException, TException {
try {
logger.info("Updating timestamp to " + timestampBoost + " variables for document " + docId);
this.indexer.updateTimestamp(docId, timestampBoost);
} catch (RuntimeException e) {
logger.error("RuntimeException while processing updateTimestampBoost.", e);
throw new IndextankException(e.getMessage());
}
}
@Override
public void addScoreFunction(int functionIndex, String definition) throws IndextankException, TException {
try {
logger.info("Updating function " + functionIndex + " to definition " + definition);
this.indexer.addScoreFunction(functionIndex, definition);
} catch (Exception e) {
logger.error("Exception while processing addScoreFunction.", e);
throw new IndextankException(e.getMessage());
}
}
@Override
public void removeScoreFunction(int functionIndex) throws IndextankException, TException {
try {
logger.info("Removing function " + functionIndex);
this.indexer.removeScoreFunction(functionIndex);
} catch (RuntimeException e) {
logger.error("RuntimeException while processing removeScoreFunction.", e);
throw new IndextankException(e.getMessage());
}
}
@Override
public Map<Integer,String> listScoreFunctions() throws IndextankException, TException {
try {
Map<Integer, String> functions = this.indexer.listScoreFunctions();
logger.info("Listed " + functions.size() + " functions");
return functions;
} catch (RuntimeException e) {
logger.error("RuntimeException while processing listScoreFunctions.", e);
throw new IndextankException();
}
}
@Override
public Map<String, String> get_stats() throws IndextankException, TException {
try {
Map<String, String> stats = this.indexer.getStats();
logger.info("Returned stats");
return stats;
} catch (RuntimeException e) {
logger.error("RuntimeException while processing listScoreFunctions.", e);
throw new IndextankException();
}
}
@Override
public void force_gc() throws IndextankException, TException {
try {
Runtime.getRuntime().gc();
logger.info("Forced GC");
} catch (RuntimeException e) {
logger.error("RuntimeException while running Runtime.gc().", e);
throw new IndextankException();
}
}
}
}