/*
* Copyright (c) 2008-2011 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.db.client.impl;
import com.emc.storageos.coordinator.client.model.Constants;
import com.emc.storageos.coordinator.client.service.CoordinatorClient;
import com.emc.storageos.coordinator.exceptions.RetryableCoordinatorException;
import com.emc.storageos.coordinator.common.Configuration;
import com.emc.storageos.coordinator.common.Service;
import com.google.common.base.Supplier;
import com.netflix.astyanax.connectionpool.Host;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URI;
import java.util.*;
/**
* Plugs into astyanax connection pool for host discovery. It's implemented using
* coordinator db service information
*/
public class HostSupplierImpl implements Supplier<List<Host>> {
private static final Logger _log = LoggerFactory.getLogger(HostSupplierImpl.class);
private static final int SLEEP_BETWEEN_RETRY = 10000; // 10 sec
private static final int NUM_RETRY_COUNT = 60; // total wait time 10 minutes
private CoordinatorClient _coordinator;
private String _version;
private String dbSvcName;
/**
* Coordinator dependency
*
* @param coordinator
*/
public void setCoordinatorClient(CoordinatorClient coordinator) {
_coordinator = coordinator;
}
public CoordinatorClient getCoordinatorClient() {
return _coordinator;
}
/**
* DB client version in use
*
* @param version
*/
public void setDbClientVersion(String version) {
_version = version;
}
public String getDbClientVersion() {
return _version;
}
@Override
public List<Host> get() {
int sleepDuration = SLEEP_BETWEEN_RETRY;
List<Host> hosts = null;
for (int i = 1; i <= NUM_RETRY_COUNT; i++) {
try {
hosts = internalGet();
} catch (RuntimeException ignore) {
_log.warn("ignore get host fail:{}", ignore.getMessage());
}
if ((hosts == null) || (hosts.isEmpty())) {
_log.warn("hostsupplier is empty. May be dbsvc hasn't started yet. waiting for " + sleepDuration + " msec");
try {
Thread.sleep(sleepDuration);
} catch (InterruptedException ignore) {
Thread.currentThread().interrupt();
}
} else {
return hosts;
}
}
return hosts;
}
public List<Host> internalGet() {
try {
_log.debug("getting hosts for " + dbSvcName + "; version = " + _version);
boolean isGeodb = Constants.GEODBSVC_NAME.equals(dbSvcName);
List<Service> service = _coordinator.locateAllServices(dbSvcName, _version, (String) null, null);
List<Host> hostList = new ArrayList<Host>(service.size());
for (int i = 0; i < service.size(); i++) {
Service svc = service.get(i);
if (isGeodb && isDbReinitializing(svc)) {
_log.debug("Ignore host {} because its geodb is reinitialzing", svc.getId());
continue;
}
URI hostUri = svc.getEndpoint();
_log.debug("Found " + svc.getName() + "; host = " + hostUri.getHost() + "; port = " + hostUri.getPort());
hostList.add(new Host(String.format(
"%1$s:%2$d", hostUri.getHost(), hostUri.getPort()), hostUri.getPort()));
}
_log.debug("dbsvc endpoint refreshed");
return hostList;
} catch (RetryableCoordinatorException e) {
_log.warn("no dbsvc instance running. Coordinator exception message: {}", e.getMessage());
} catch (Exception e) {
_log.error("dbsvc lookup failure", e);
}
return Collections.emptyList();
}
private boolean isDbReinitializing(Service serviceInfo) {
String configKind = _coordinator.getDbConfigPath(serviceInfo.getName());
Configuration config = _coordinator.queryConfiguration(_coordinator.getSiteId(), configKind, serviceInfo.getId());
String value = config.getConfig(Constants.REINIT_DB);
return (value != null && Boolean.parseBoolean(value));
}
public String getDbSvcName() {
return dbSvcName;
}
public void setDbSvcName(String dbSvcName) {
this.dbSvcName = dbSvcName;
}
}