package ibis.ipl.impl.multi;
import ibis.ipl.Ibis;
import ibis.ipl.IbisConfigurationException;
import ibis.ipl.IbisIdentifier;
import ibis.ipl.NoSuchPropertyException;
import ibis.ipl.Registry;
import ibis.util.ThreadPool;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MultiRegistry implements Registry{
private static final Logger logger = LoggerFactory.getLogger(MultiRegistry.class);
private final MultiIbis ibis;
private final ManageableMapper ManageableMapper;
private final HashMap<String, Registry>subRegistries;
final Map<MultiIbisIdentifier, MultiIbisIdentifier>joined = Collections.synchronizedMap(new HashMap<MultiIbisIdentifier, MultiIbisIdentifier>());
final Map<MultiIbisIdentifier, MultiIbisIdentifier>left = Collections.synchronizedMap(new HashMap<MultiIbisIdentifier, MultiIbisIdentifier>());
final Map<MultiIbisIdentifier, MultiIbisIdentifier>died = Collections.synchronizedMap(new HashMap<MultiIbisIdentifier, MultiIbisIdentifier>());
final Map<String, MultiIbisIdentifier>elected = Collections.synchronizedMap(new HashMap<String, MultiIbisIdentifier>());
@SuppressWarnings({ "unchecked", "rawtypes" })
public MultiRegistry(MultiIbis multiIbis) {
this.ibis = multiIbis;
subRegistries = new HashMap<String, Registry>();
for (String ibisName:ibis.subIbisMap.keySet()) {
Ibis subIbis = ibis.subIbisMap.get(ibisName);
if (logger.isDebugEnabled()) {
logger.debug("Registry for: " + ibisName + " : "+ subIbis.registry());
}
subRegistries.put(ibisName, subIbis.registry());
}
ManageableMapper = new ManageableMapper((Map)subRegistries);
}
public void assumeDead(IbisIdentifier ibisIdentifier) throws IOException {
for(String ibisName:subRegistries.keySet()) {
Registry subRegistry = subRegistries.get(ibisName);
subRegistry.assumeDead(((MultiIbisIdentifier)ibisIdentifier).subIdForIbis(ibisName));
}
}
public IbisIdentifier[] diedIbises() {
HashMap<IbisIdentifier, String> theDead = new HashMap<IbisIdentifier, String>();
for (String ibisName:subRegistries.keySet()) {
Registry subRegistry = subRegistries.get(ibisName);
IbisIdentifier[] ids = subRegistry.diedIbises();
for(int i=0; i<ids.length; i++) {
try {
theDead.put(ibis.mapIdentifier(ids[i], ibisName), ibisName);
} catch (IOException e) {
// TODO Should we be ignoring this
}
}
}
return theDead.keySet().toArray(new IbisIdentifier[theDead.size()]);
}
public void disableEvents() {
for (Registry subRegistry:subRegistries.values()) {
subRegistry.disableEvents();
}
}
public IbisIdentifier elect(String electionName) throws IOException {
return elect(electionName, 0);
}
private final class ElectionRunner implements Runnable {
private final Registry subRegistry;
private final String electionName;
private final long timeoutMillis;
private final List<IbisIdentifierWrapper>elected;
private final String ibisName;
public ElectionRunner(String ibisName, Registry subRegistry, List<IbisIdentifierWrapper>elected, String electionName, long timeoutMillis) {
this.subRegistry = subRegistry;
this.electionName = electionName;
this.timeoutMillis = timeoutMillis;
this.elected = elected;
this.ibisName = ibisName;
}
public void run() {
IbisIdentifier winner = null;
try {
winner = subRegistry.elect(electionName, timeoutMillis);
if (logger.isDebugEnabled()) {
logger.debug("SubRegistry: " + subRegistry + " elected: " + winner);
}
} catch (IOException e) {
// Ignored
}
synchronized(elected) {
if (winner != null) {
elected.add(new IbisIdentifierWrapper(ibisName, winner));
}
elected.notify();
}
}
}
public IbisIdentifier elect(final String electionName, final long timeoutMillis)
throws IOException {
if (subRegistries.size() > 0) {
// TODO: Need to kick off these elections in parallel
// TODO This is dumb stupid election management that wont work a lot of the time
final List<IbisIdentifierWrapper>elected = new ArrayList<IbisIdentifierWrapper>();
synchronized (elected) {
for (String ibisName: subRegistries.keySet()) {
Registry subRegistry = subRegistries.get(ibisName);
ThreadPool.createNew(new ElectionRunner(ibisName, subRegistry, elected, electionName, timeoutMillis), "Election: " + electionName);
}
while (elected.size() < subRegistries.size()) {
try {
// Wait for the timeout
if (logger.isDebugEnabled()) {
logger.debug("Waiting for election: " + electionName + " count: " + elected.size()+ " of: " + subRegistries.size() + " for: " + timeoutMillis);
}
elected.wait(timeoutMillis);
if (logger.isDebugEnabled()) {
logger.debug("Woke up election: " + electionName + " count:" + elected.size() + " of: " + subRegistries.size());
}
}
catch (InterruptedException e) {
// Ignored
}
}
if (!elected.isEmpty()) {
Collections.sort(elected);
if (logger.isDebugEnabled()) {
logger.debug("Elected: " + elected.get(0));
}
return ibis.mapIdentifier(elected.get(0).id, elected.get(0).ibisName);
}
else {
throw new Error("No election results!");
}
}
}
else {
throw new Error("No Subregistries to support elections.");
}
}
public void enableEvents() {
for (Registry subRegistry:subRegistries.values()) {
subRegistry.enableEvents();
}
}
public IbisIdentifier getElectionResult(String electionName)
throws IOException {
return getElectionResult(electionName, 0);
}
public IbisIdentifier getElectionResult(String electionName,
long timeoutMillis) throws IOException {
IbisIdentifier results = null;
if (logger.isDebugEnabled()) {
logger.debug("Getting Election Results for: " + electionName + " timeout: " + timeoutMillis);
}
timeoutMillis = timeoutMillis / subRegistries.size();
// TODO This is dumb stupid election management that wont work a lot of the time
ArrayList<IbisIdentifier>elected = new ArrayList<IbisIdentifier>();
for (String ibisName: subRegistries.keySet()) {
Registry subRegistry = subRegistries.get(ibisName);
// TODO: This expands the timeout.
IbisIdentifier winner = subRegistry.getElectionResult(electionName, timeoutMillis);
if (winner != null) {
elected.add(ibis.mapIdentifier(winner, ibisName));
}
}
if (!elected.isEmpty()) {
Collections.sort(elected);
results = elected.get(0);
}
if (logger.isDebugEnabled()) {
logger.debug("ElectionResult : " + electionName + " : "+ results);
}
return results;
}
public int getPoolSize() {
int poolSize = 0;
for (Registry subRegistry: subRegistries.values()) {
poolSize += subRegistry.getPoolSize();
}
return poolSize;
}
public String getPoolName() {
//FIXME:does this make sense? -Niels
return ibis.identifier().poolName();
}
public long getSequenceNumber(String name) throws IOException {
// TODO: Any way to support sequences?
throw new IOException("Sequences not supported!");
}
public IbisIdentifier[] joinedIbises() {
HashMap<IbisIdentifier, String> theJoined = new HashMap<IbisIdentifier, String>();
for (String ibisName:subRegistries.keySet()) {
Registry subRegistry = subRegistries.get(ibisName);
IbisIdentifier[] ids = subRegistry.joinedIbises();
for(int i=0; i<ids.length; i++) {
try {
theJoined.put(ibis.mapIdentifier(ids[i], ibisName), ibisName);
} catch (IOException e) {
// TODO Should we be ignoring this?
}
}
}
return theJoined.keySet().toArray(new IbisIdentifier[theJoined.size()]);
}
public IbisIdentifier[] leftIbises() {
HashMap<IbisIdentifier, String> theLeft = new HashMap<IbisIdentifier, String>();
for (String ibisName:subRegistries.keySet()) {
Registry subRegistry = subRegistries.get(ibisName);
IbisIdentifier[] ids = subRegistry.leftIbises();
for(int i=0; i<ids.length; i++) {
try {
theLeft.put(ibis.mapIdentifier(ids[i], ibisName), ibisName);
} catch (IOException e) {
// TODO Should we be ignoring this?
}
}
}
return theLeft.keySet().toArray(new IbisIdentifier[theLeft.size()]);
}
public void maybeDead(IbisIdentifier ibisIdentifier) throws IOException {
for (String ibisName:subRegistries.keySet()) {
Registry subRegistry = subRegistries.get(ibisName);
subRegistry.maybeDead(ibis.mapIdentifier(ibisIdentifier, ibisName));
}
}
public String[] receivedSignals() {
HashMap<String, String> theSignals = new HashMap<String, String>();
for (Registry subRegistry:subRegistries.values()) {
String[] signals = subRegistry.receivedSignals();
for(int i=0; i<signals.length; i++) {
theSignals.put(signals[i], signals[i]);
}
}
return theSignals.keySet().toArray(new String[theSignals.size()]);
}
public void signal(String signal, IbisIdentifier... ibisIdentifiers)
throws IOException {
IbisIdentifier[] ids = new IbisIdentifier[ibisIdentifiers.length];
for(String ibisName:subRegistries.keySet()) {
Registry subRegistry = subRegistries.get(ibisName);
for (int i=0; i<ids.length; i++) {
ids[i] = ((MultiIbisIdentifier)ibisIdentifiers[i]).subIdForIbis(ibisName);
}
subRegistry.signal(signal, ids);
}
}
public boolean isClosed() {
//FIXME: is this correct? - Niels
for (Registry subRegistry:subRegistries.values()) {
if (!subRegistry.isClosed()) {
return false;
}
}
return true;
}
public void waitUntilPoolClosed() {
for (Registry subRegistry:subRegistries.values()) {
subRegistry.waitUntilPoolClosed();
}
}
public String getManagementProperty(String key)
throws NoSuchPropertyException {
return ManageableMapper.getManagementProperty(key);
}
public Map<String, String> managementProperties() {
return ManageableMapper.managementProperties();
}
public void printManagementProperties(PrintStream stream) {
ManageableMapper.printManagementProperties(stream);
}
public void setManagementProperties(Map<String, String> properties)
throws NoSuchPropertyException {
ManageableMapper.setManagementProperties(properties);
}
public void setManagementProperty(String key, String value)
throws NoSuchPropertyException {
ManageableMapper.setManagementProperty(key, value);
}
public boolean hasTerminated() {
//FIXME: implement termination for this registry
throw new IbisConfigurationException(
"termination not supported by MultiRegistry");
}
public void terminate() throws IOException {
throw new IbisConfigurationException(
"termination not supported by MultiRegistry");
}
public IbisIdentifier waitUntilTerminated() {
throw new IbisConfigurationException(
"termination not supported by MultiRegistry");
}
}