/*
* Copyright 2012 NGDATA nv
*
* 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 org.lilyproject.repotestfw;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.lilyproject.repository.model.api.RepositoryDefinition;
import org.lilyproject.util.hbase.RepoAndTableUtil;
import org.lilyproject.repository.master.RepositoryMaster;
import com.ngdata.sep.EventListener;
import com.ngdata.sep.SepModel;
import com.ngdata.sep.impl.SepConsumer;
import com.ngdata.sep.impl.SepModelImpl;
import org.apache.avro.ipc.NettyServer;
import org.apache.avro.ipc.Server;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.zookeeper.KeeperException;
import org.lilyproject.avro.AvroConverter;
import org.lilyproject.avro.AvroLily;
import org.lilyproject.avro.AvroLilyImpl;
import org.lilyproject.avro.LilySpecificResponder;
import org.lilyproject.hadooptestfw.HBaseProxy;
import org.lilyproject.repository.api.BlobManager;
import org.lilyproject.repository.api.BlobStoreAccess;
import org.lilyproject.repository.api.BlobStoreAccessFactory;
import org.lilyproject.repository.api.IdGenerator;
import org.lilyproject.repository.api.RecordFactory;
import org.lilyproject.repository.api.Repository;
import org.lilyproject.repository.api.RepositoryException;
import org.lilyproject.repository.api.RepositoryManager;
import org.lilyproject.repository.api.TableManager;
import org.lilyproject.repository.api.TypeManager;
import org.lilyproject.repository.impl.AbstractSchemaCache;
import org.lilyproject.repository.impl.BlobManagerImpl;
import org.lilyproject.repository.impl.BlobStoreAccessConfig;
import org.lilyproject.repository.impl.DFSBlobStoreAccess;
import org.lilyproject.repository.impl.HBaseBlobStoreAccess;
import org.lilyproject.repository.impl.HBaseRepository;
import org.lilyproject.repository.impl.HBaseRepositoryManager;
import org.lilyproject.repository.impl.HBaseTypeManager;
import org.lilyproject.repository.impl.InlineBlobStoreAccess;
import org.lilyproject.repository.impl.RecordFactoryImpl;
import org.lilyproject.repository.impl.TableManagerImpl;
import org.lilyproject.repository.impl.CoreRepositoryMasterHook;
import org.lilyproject.repository.impl.SchemaCache;
import org.lilyproject.repository.impl.SizeBasedBlobStoreAccessFactory;
import org.lilyproject.repository.impl.RepoTableKey;
import org.lilyproject.repository.impl.id.IdGeneratorImpl;
import org.lilyproject.repository.remote.AvroLilyTransceiver;
import org.lilyproject.repository.remote.RemoteRepositoryManager;
import org.lilyproject.repository.remote.RemoteTypeManager;
import org.lilyproject.repository.spi.RecordUpdateHook;
import org.lilyproject.sep.LilyEventPublisherManager;
import org.lilyproject.sep.LilyPayloadExtractor;
import org.lilyproject.sep.ZooKeeperItfAdapter;
import org.lilyproject.repository.master.RepositoryMasterHook;
import org.lilyproject.repository.model.api.RepositoryModel;
import org.lilyproject.repository.model.impl.RepositoryModelImpl;
import org.lilyproject.util.LilyInfo;
import org.lilyproject.util.hbase.HBaseTableFactory;
import org.lilyproject.util.hbase.HBaseTableFactoryImpl;
import org.lilyproject.util.hbase.LilyHBaseSchema.Table;
import org.lilyproject.util.io.Closer;
import org.lilyproject.util.zookeeper.ZkUtil;
import org.lilyproject.util.zookeeper.ZooKeeperItf;
/**
* Helper class to instantiate and wire all the repository related services.
*/
public class RepositorySetup {
private HBaseProxy hbaseProxy;
private Configuration hadoopConf;
private ZooKeeperItf zk;
private HBaseTableFactory hbaseTableFactory;
private RepositoryModel repositoryModel;
private RepositoryMaster repositoryMaster;
private IdGenerator idGenerator;
private HBaseTypeManager typeManager;
private RemoteTypeManager remoteTypeManager;
private RepositoryManager repositoryManager;
private RemoteRepositoryManager remoteRepositoryManager;
private TableManager tableManager;
private Server lilyServer;
private BlobStoreAccessFactory blobStoreAccessFactory;
private BlobStoreAccessFactory remoteBlobStoreAccessFactory;
private BlobManager blobManager;
private BlobManager remoteBlobManager;
private SepModel sepModel;
private SepConsumer sepConsumer;
private LilyEventPublisherManager eventPublisherManager;
private boolean coreSetup;
private boolean typeManagerSetup;
private boolean repositoryManagerSetup;
private long hbaseBlobLimit = -1;
private long inlineBlobLimit = -1;
private List<RecordUpdateHook> recordUpdateHooks = Collections.emptyList();
private RemoteTestSchemaCache remoteSchemaCache;
public void setRecordUpdateHooks(List<RecordUpdateHook> recordUpdateHooks) {
this.recordUpdateHooks = recordUpdateHooks;
}
public void setupCore() throws Exception {
if (coreSetup) {
return;
}
hbaseProxy = new HBaseProxy();
hbaseProxy.start();
hadoopConf = hbaseProxy.getConf();
zk = ZkUtil.connect(hbaseProxy.getZkConnectString(), 10000);
hbaseTableFactory = new HBaseTableFactoryImpl(hadoopConf);
repositoryModel = new RepositoryModelImpl(zk);
repositoryMaster = new RepositoryMaster(zk, repositoryModel, new DummyLilyInfo(),
Collections.<RepositoryMasterHook>singletonList(new CoreRepositoryMasterHook(hbaseTableFactory, hbaseProxy.getConf())));
repositoryMaster.start();
coreSetup = true;
}
public void setupTypeManager() throws Exception {
if (typeManagerSetup) {
return;
}
idGenerator = new IdGeneratorImpl();
typeManager = new HBaseTypeManager(idGenerator, hadoopConf, zk, hbaseTableFactory);
typeManagerSetup = true;
}
public void setupRepository() throws Exception {
setupRepository(RepoAndTableUtil.DEFAULT_REPOSITORY);
}
public void setupRepository(String repositoryName) throws Exception {
if (repositoryManagerSetup) {
return;
}
setupTypeManager();
if (!repositoryModel.repositoryExistsAndActive(repositoryName)) {
repositoryModel.create(repositoryName);
repositoryModel.waitUntilRepositoryInState(repositoryName, RepositoryDefinition.RepositoryLifecycleState
.ACTIVE, 100000);
}
blobStoreAccessFactory = createBlobAccess();
blobManager = new BlobManagerImpl(hbaseTableFactory, blobStoreAccessFactory, false);
RecordFactory recordFactory = new RecordFactoryImpl();
repositoryManager = new HBaseRepositoryManager(typeManager, idGenerator, recordFactory, hbaseTableFactory,
blobManager, hadoopConf, repositoryModel) {
@Override
protected Repository createRepository(RepoTableKey key) throws InterruptedException, RepositoryException {
HBaseRepository repository = (HBaseRepository)super.createRepository(key);
repository.setRecordUpdateHooks(recordUpdateHooks);
return repository;
}
};
sepModel = new SepModelImpl(new ZooKeeperItfAdapter(zk), hadoopConf);
eventPublisherManager = new LilyEventPublisherManager(hbaseTableFactory);
tableManager = new TableManagerImpl(repositoryName, hadoopConf, hbaseTableFactory);
if (!tableManager.tableExists(Table.RECORD.name)) {
tableManager.createTable(Table.RECORD.name);
}
repositoryManagerSetup = true;
}
private BlobStoreAccessFactory createBlobAccess() throws Exception {
DFSBlobStoreAccess dfsBlobStoreAccess = new DFSBlobStoreAccess(hbaseProxy.getBlobFS(), new Path("/lily/blobs"));
BlobStoreAccess hbaseBlobStoreAccess = new HBaseBlobStoreAccess(hadoopConf);
BlobStoreAccess inlineBlobStoreAccess = new InlineBlobStoreAccess();
BlobStoreAccessConfig blobStoreAccessConfig = new BlobStoreAccessConfig(dfsBlobStoreAccess.getId());
if (hbaseBlobLimit != -1) {
blobStoreAccessConfig.setLimit(hbaseBlobStoreAccess.getId(), hbaseBlobLimit);
}
if (inlineBlobLimit != -1) {
blobStoreAccessConfig.setLimit(inlineBlobStoreAccess.getId(), inlineBlobLimit);
}
List<BlobStoreAccess> blobStoreAccesses =
Arrays.asList(dfsBlobStoreAccess, hbaseBlobStoreAccess, inlineBlobStoreAccess);
return new SizeBasedBlobStoreAccessFactory(blobStoreAccesses, blobStoreAccessConfig);
}
/**
* Set the size limits for the inline and HBase blobs, set to -1 to disable one of these
* stores.
*/
public void setBlobLimits(long inlineBlobLimit, long hbaseBlobLimit) {
this.inlineBlobLimit = inlineBlobLimit;
this.hbaseBlobLimit = hbaseBlobLimit;
}
public void setupRemoteAccess() throws Exception {
lilyServer = new NettyServer(
new LilySpecificResponder(AvroLily.class, new AvroLilyImpl(repositoryManager, typeManager)
), new InetSocketAddress(0));
lilyServer.start();
final AvroConverter avroConverter = new AvroConverter();
final InetSocketAddress remoteAddr = new InetSocketAddress(lilyServer.getPort());
remoteSchemaCache = new RemoteTestSchemaCache(zk);
remoteTypeManager = new RemoteTypeManager(remoteAddr, avroConverter, idGenerator, zk, remoteSchemaCache);
remoteSchemaCache.setTypeManager(remoteTypeManager);
RecordFactory recordFactory = new RecordFactoryImpl();
remoteRepositoryManager = new RemoteRepositoryManager(remoteTypeManager, idGenerator, recordFactory,
new AvroLilyTransceiver(remoteAddr), avroConverter, blobManager, hbaseTableFactory, repositoryModel);
remoteBlobStoreAccessFactory = createBlobAccess();
remoteBlobManager = new BlobManagerImpl(hbaseTableFactory, remoteBlobStoreAccessFactory, false);
remoteSchemaCache.start();
}
/**
* Wait until all currently queued SEP events are processed.
*
* <p>New events that are generated after/during a call to this method will not be waited for.</p>
*/
public void waitForSepProcessing() throws Exception {
long timeout = 60000L;
boolean success = hbaseProxy.waitOnReplication(timeout);
if (!success) {
throw new Exception("Events were not processed within a timeout of " + timeout + "ms");
}
}
public void stop() throws InterruptedException {
Closer.close(sepConsumer);
Closer.close(remoteSchemaCache);
Closer.close(remoteTypeManager);
Closer.close(typeManager);
Closer.close(remoteRepositoryManager);
Closer.close(repositoryManager);
if (lilyServer != null) {
lilyServer.close();
lilyServer.join();
}
Closer.close(repositoryMaster);
Closer.close(zk);
Closer.close(hbaseProxy);
coreSetup = false;
repositoryManagerSetup = false;
typeManagerSetup = false;
}
public ZooKeeperItf getZk() {
return zk;
}
public RepositoryModel getRepositoryModel() {
return repositoryModel;
}
public TypeManager getRemoteTypeManager() {
return remoteTypeManager;
}
public RepositoryManager getRepositoryManager() {
return repositoryManager;
}
public TableManager getTableManager() {
return tableManager;
}
public RemoteRepositoryManager getRemoteRepositoryManager() {
return remoteRepositoryManager;
}
public SepModel getSepModel() {
return sepModel;
}
public LilyEventPublisherManager getEventPublisherManager() {
return eventPublisherManager;
}
public void stopSepEventSlave() {
if (sepConsumer == null || !sepConsumer.isRunning()) {
throw new IllegalStateException("No SepEventSlave to stop");
}
sepConsumer.stop();
sepConsumer = null;
}
/**
* Start a SEP event processor. Only a single SEP event processor is supported within the
* context of this class.
*
* @param subscriptionId The id of the subscription for which the slave will process events
* @param eventListener The listener to handle incoming events
*/
public void startSepEventSlave(String subscriptionId, EventListener eventListener) throws Exception {
if (sepConsumer != null) {
throw new IllegalStateException("There is already a SepEventSlave running, stop it first");
}
sepConsumer = new SepConsumer(subscriptionId, System.currentTimeMillis(), eventListener, 1, "localhost",
new ZooKeeperItfAdapter(zk), hadoopConf, new LilyPayloadExtractor());
sepConsumer.start();
}
/**
* Returns a default typemanager.
*/
public TypeManager getTypeManager() {
return typeManager;
}
/**
* Returns a new instance of a HBaseTypeManager, different than the default
* typemanager.
*/
public TypeManager getNewTypeManager() throws IOException, InterruptedException, KeeperException,
RepositoryException {
return new HBaseTypeManager(new IdGeneratorImpl(), hadoopConf, zk, hbaseTableFactory);
}
public IdGenerator getIdGenerator() {
return idGenerator;
}
public Configuration getHadoopConf() {
return hadoopConf;
}
public HBaseTableFactory getHbaseTableFactory() {
return hbaseTableFactory;
}
public BlobStoreAccessFactory getBlobStoreAccessFactory() {
return blobStoreAccessFactory;
}
public BlobStoreAccessFactory getRemoteBlobStoreAccessFactory() {
return remoteBlobStoreAccessFactory;
}
public BlobManager getBlobManager() {
return blobManager;
}
public BlobManager getRemoteBlobManager() {
return remoteBlobManager;
}
public HBaseProxy getHBaseProxy() {
return hbaseProxy;
}
private class RemoteTestSchemaCache extends AbstractSchemaCache implements SchemaCache {
private TypeManager typeManager;
RemoteTestSchemaCache(ZooKeeperItf zooKeeper) {
super(zooKeeper);
}
public void setTypeManager(TypeManager typeManager) {
this.typeManager = typeManager;
}
@Override
protected TypeManager getTypeManager() {
return typeManager;
}
}
private static class DummyLilyInfo implements LilyInfo {
@Override
public void setIndexerMaster(boolean indexerMaster) {
}
@Override
public void setRepositoryMaster(boolean repositoryMaster) {
}
@Override
public String getVersion() {
return null;
}
@Override
public Set<String> getHostnames() {
return null;
}
@Override
public boolean isIndexerMaster() {
return false;
}
@Override
public boolean isRepositoryMaster() {
return false;
}
}
}