
io.joynr.messaging.routing.RoutingTableImpl Maven / Gradle / Ivy
/*
* #%L
* %%
* Copyright (C) 2011 - 2017 BMW Car IT GmbH
* %%
* 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.
* #L%
*/
package io.joynr.messaging.routing;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import static io.joynr.messaging.ConfigurableMessagingSettings.PROPERTY_ROUTING_TABLE_GRACE_PERIOD_MS;
import java.util.Iterator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import io.joynr.exceptions.JoynrRuntimeException;
import joynr.system.RoutingTypes.Address;
@Singleton
public class RoutingTableImpl implements RoutingTable {
private static final Logger logger = LoggerFactory.getLogger(RoutingTableImpl.class);
private static class RoutingEntry {
RoutingEntry(Address address, boolean isGloballyVisible, long expiryDateMs, boolean isSticky) {
setAddress(address);
setIsGloballyVisible(isGloballyVisible);
this.expiryDateMs = expiryDateMs;
this.isSticky = isSticky;
}
public Address getAddress() {
return address;
}
public boolean getIsGloballyVisible() {
return isGloballyVisible;
}
public long getExpiryDateMs() {
return expiryDateMs;
}
public boolean getIsSticky() {
return isSticky;
}
public void setAddress(Address address) {
this.address = address;
}
public void setIsGloballyVisible(boolean isGloballyVisible) {
this.isGloballyVisible = isGloballyVisible;
}
public void setExpiryDateMs(long expiryDateMs) {
this.expiryDateMs = expiryDateMs;
}
public void setIsSticky(boolean isSticky) {
this.isSticky = isSticky;
}
private Address address;
private boolean isGloballyVisible;
private long expiryDateMs;
private boolean isSticky;
}
private ConcurrentMap hashMap = new ConcurrentHashMap<>();
private final long routingTableGracePeriodMs;
@Inject
public RoutingTableImpl(@Named(PROPERTY_ROUTING_TABLE_GRACE_PERIOD_MS) long routingTableGracePeriodMs) {
this.routingTableGracePeriodMs = routingTableGracePeriodMs;
}
@Override
public Address get(String participantId) {
logger.trace("entering get(participantId={})", participantId);
dumpRoutingTableEntry();
RoutingEntry routingEntry = hashMap.get(participantId);
if (routingEntry == null) {
logger.trace("leaving get(participantId={}) = null", participantId);
return null;
}
logger.trace("leaving get(participantId={}) = {}", participantId, routingEntry.getAddress());
return routingEntry.getAddress();
}
private void dumpRoutingTableEntry() {
if (logger.isTraceEnabled()) {
StringBuilder message = new StringBuilder("Routing table entries:\n");
for (Entry eachEntry : hashMap.entrySet()) {
message.append("\t> ")
.append(eachEntry.getKey())
.append("\t-\t")
.append(eachEntry.getValue().address)
.append("\t-\t")
.append(eachEntry.getValue().isGloballyVisible)
.append("\t-\t")
.append(eachEntry.getValue().expiryDateMs)
.append("\t-\t")
.append(eachEntry.getValue().isSticky)
.append("\n");
}
logger.trace(message.toString());
}
}
@Override
public void put(String participantId,
Address address,
boolean isGloballyVisible,
long expiryDateMs,
boolean sticky,
boolean allowUpdate) {
try {
expiryDateMs = Math.addExact(expiryDateMs, routingTableGracePeriodMs);
} catch (ArithmeticException e) {
expiryDateMs = Long.MAX_VALUE;
}
RoutingEntry routingEntry = new RoutingEntry(address, isGloballyVisible, expiryDateMs, sticky);
synchronized (this) {
RoutingEntry result = hashMap.putIfAbsent(participantId, routingEntry);
final boolean routingEntryAlreadyPresent = result != null;
if (!routingEntryAlreadyPresent) {
logger.trace("put(participantId={}, address={}, isGloballyVisible={}, expiryDateMs={}, sticky={}) successfully into routing table",
participantId,
address,
isGloballyVisible,
expiryDateMs,
sticky);
return;
}
final boolean routingEntryChanged = !address.equals(result.getAddress())
|| result.getIsGloballyVisible() != isGloballyVisible;
if (routingEntryChanged) {
if (allowUpdate) {
logger.debug("put(participantId={}, address={}, isGloballyVisible={}, expiryDateMs={}, sticky={}). Replacing previous entry with address={}, isGloballyVisible={}, expiryDateMs={}, sticky={}",
participantId,
address,
isGloballyVisible,
expiryDateMs,
sticky,
result.address,
result.isGloballyVisible,
result.expiryDateMs,
result.isSticky);
mergeRoutingEntryAttributes(routingEntry, result.getExpiryDateMs(), result.getIsSticky());
hashMap.put(participantId, routingEntry);
} else {
logger.warn("unable to update(participantId={}, address={}, isGloballyVisible={}, expiryDateMs={}, sticky={}) into routing table,"
+ " since the participant ID is already associated with routing entry address={}, isGloballyVisible={}",
participantId,
address,
isGloballyVisible,
expiryDateMs,
sticky,
result.address,
result.isGloballyVisible);
}
} else {
logger.trace("put(participantId={}, address={}, isGloballyVisible={}, expiryDateMs={}, sticky={}): Entry exists. Updating expiryDate and sticky-flag",
participantId,
address,
isGloballyVisible,
expiryDateMs,
sticky);
mergeRoutingEntryAttributes(result, expiryDateMs, sticky);
}
}
}
private void mergeRoutingEntryAttributes(RoutingEntry entry, long expiryDateMs, boolean isSticky) {
// extend lifetime, if required
if (entry.getExpiryDateMs() < expiryDateMs) {
entry.setExpiryDateMs(expiryDateMs);
}
// make entry sticky, if required
// if entry already was sticky, and new entry is not, keep the sticky attribute
if (isSticky && !entry.getIsSticky()) {
entry.setIsSticky(true);
}
}
@Override
public boolean containsKey(String participantId) {
boolean containsKey = hashMap.containsKey(participantId);
logger.trace("checking for participant: {} success: {}", participantId, containsKey);
if (!containsKey) {
dumpRoutingTableEntry();
}
return containsKey;
}
@Override
public boolean getIsGloballyVisible(String participantId) {
RoutingEntry routingEntry = hashMap.get(participantId);
if (routingEntry == null) {
throw new JoynrRuntimeException("participantId doesn't exist in the routing table");
}
return routingEntry.getIsGloballyVisible();
}
@Override
public void setIsSticky(String participantId, boolean isSticky) {
RoutingEntry routingEntry = hashMap.get(participantId);
if (routingEntry == null) {
throw new JoynrRuntimeException("participantId doesn't exist in the routing table");
}
routingEntry.setIsSticky(isSticky);
}
@Override
public long getExpiryDateMs(String participantId) {
RoutingEntry routingEntry = hashMap.get(participantId);
if (routingEntry == null) {
throw new JoynrRuntimeException("participantId doesn't exist in the routing table");
}
return routingEntry.getExpiryDateMs();
}
@Override
public boolean getIsSticky(String participantId) {
RoutingEntry routingEntry = hashMap.get(participantId);
if (routingEntry == null) {
throw new JoynrRuntimeException("participantId doesn't exist in the routing table");
}
return routingEntry.getIsSticky();
}
@Override
public void remove(String participantId) {
RoutingEntry routingEntry = hashMap.get(participantId);
if (routingEntry != null) {
logger.trace("removing(participantId={}, address={}, isGloballyVisible={}, expiryDateMs={}, sticky={}) from routing table",
participantId,
routingEntry.getAddress(),
routingEntry.getIsGloballyVisible(),
routingEntry.getExpiryDateMs(),
routingEntry.getIsSticky());
}
hashMap.remove(participantId);
}
@Override
public void apply(AddressOperation addressOperation) {
if (addressOperation == null) {
throw new IllegalArgumentException();
}
for (RoutingEntry routingEntry : hashMap.values()) {
addressOperation.perform(routingEntry.getAddress());
}
}
public void purge() {
logger.trace("purge: begin");
Iterator> it = hashMap.entrySet().iterator();
long currentTimeMillis = System.currentTimeMillis();
while (it.hasNext()) {
Entry e = it.next();
if (logger.isTraceEnabled()) {
logger.trace("check: participantId = {}, sticky = {}, expiryDateMs = {}, now = {}",
e.getKey(),
e.getValue().getIsSticky(),
e.getValue().getExpiryDateMs(),
currentTimeMillis);
}
if (!e.getValue().getIsSticky() && e.getValue().expiryDateMs < currentTimeMillis) {
if (logger.isTraceEnabled()) {
logger.trace("purging(participantId={}, address={}, isGloballyVisible={}, expiryDateMs={}, sticky={}) from routing table",
e.getKey(),
e.getValue().getAddress(),
e.getValue().getIsGloballyVisible(),
e.getValue().getExpiryDateMs(),
e.getValue().getIsSticky());
}
it.remove();
}
}
logger.trace("purge: end");
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy