/*
* Copyright 2013 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.client.impl;
import org.lilyproject.client.RetryConf;
import org.lilyproject.repository.api.IdGenerator;
import org.lilyproject.repository.api.LTable;
import org.lilyproject.repository.api.RecordFactory;
import org.lilyproject.repository.api.Repository;
import org.lilyproject.repository.api.RepositoryException;
import org.lilyproject.repository.api.TypeManager;
import org.lilyproject.repository.impl.AbstractRepositoryManager;
import org.lilyproject.repository.impl.RepoTableKey;
import org.lilyproject.repository.spi.BaseRepositoryDecorator;
import org.lilyproject.repository.model.api.RepositoryModel;
import org.lilyproject.util.hbase.LilyHBaseSchema;
/**
* An implementation of RepositoryManager whose LRepository, LTable and TypeManager will balance operations
* over different instances of these objects. This balancing happens transparently for each method call, i.e.
* it is not necessary to retrieve new repository or table objects. Also, methods calls are wrapped to add
* automatic retrying behavior for certain kinds of IO errors (if the operation is idempotent), so that
* clients are unaware of things like a lily server process that is being restarted.
*/
public class LoadBalancingAndRetryingRepositoryManager extends AbstractRepositoryManager {
private final RetryConf retryConf;
private final LoadBalancingUtil.LBInstanceProvider<Repository> repositoryProvider;
private final LoadBalancingUtil.LBInstanceProvider<TypeManager> typeManagerProvider;
public LoadBalancingAndRetryingRepositoryManager(LoadBalancingUtil.LBInstanceProvider<Repository> repositoryProvider,
LoadBalancingUtil.LBInstanceProvider<TypeManager> typeManagerProvider, RetryConf retryConf, IdGenerator idGenerator,
RecordFactory recordFactory, RepositoryModel repositoryModel) {
super(createTypeManager(typeManagerProvider, retryConf), idGenerator, recordFactory, repositoryModel);
this.repositoryProvider = repositoryProvider;
this.typeManagerProvider = typeManagerProvider;
this.retryConf = retryConf;
}
private static TypeManager createTypeManager(LoadBalancingUtil.LBInstanceProvider<TypeManager> typeManagerProvider, RetryConf retryConf) {
return RetryUtil.getRetryingInstance(LoadBalancingUtil.getLoadBalancedInstance(typeManagerProvider,
TypeManager.class, null, null), TypeManager.class, retryConf);
}
@Override
protected Repository createRepository(RepoTableKey key) throws InterruptedException, RepositoryException {
// Note that the parent caches these instances
return new LBAwareRepository(RetryUtil.getRetryingInstance(
LoadBalancingUtil.getLoadBalancedInstance(repositoryProvider, Repository.class, key.getRepositoryName(),
key.getTableName()), Repository.class, retryConf), this, key.getRepositoryName());
}
/**
* Repository also serves as a factory for tables and a registry for other services (such as typemanager),
* and for some of these it is important to also return the load-balancing-and-retrying instances (if they would
* just call the delegate, they would return the unwrapped instances). This wrapper takes care of that.
*/
public class LBAwareRepository extends BaseRepositoryDecorator {
private TypeManager typeManager;
private AbstractRepositoryManager repositoryManager;
private String repositoryName;
/**
*
* @param repositoryManager the one which gives load-balancing-and-retrying repositories
*/
public LBAwareRepository(Repository delegate, AbstractRepositoryManager repositoryManager, String repositoryName) {
super(delegate);
this.repositoryManager = repositoryManager;
this.repositoryName = repositoryName;
}
@Override
public LTable getTable(String tableName) throws InterruptedException, RepositoryException {
return repositoryManager.getRepository(repositoryName, tableName);
}
@Override
public LTable getDefaultTable() throws InterruptedException, RepositoryException {
return repositoryManager.getRepository(repositoryName, LilyHBaseSchema.Table.RECORD.name);
}
@Override
public TypeManager getTypeManager() {
if (typeManager == null) {
typeManager = RetryUtil.getRetryingInstance(LoadBalancingUtil.getLoadBalancedInstance(typeManagerProvider,
TypeManager.class, null, null), TypeManager.class, retryConf);
}
return typeManager;
}
}
}