You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@river.apache.org by pe...@apache.org on 2012/11/20 07:57:59 UTC
svn commit: r1411564 -
/river/jtsk/trunk/src/com/sun/jini/reggie/RegistrarImpl.java
Author: peter_firmstone
Date: Tue Nov 20 06:57:58 2012
New Revision: 1411564
URL: http://svn.apache.org/viewvc?rev=1411564&view=rev
Log:
Changes to Reggie to improve synchronization issues, not a complete fix, Reggie needs a thorough refactoring to improve encapsulation for easier maintenance.
Modified:
river/jtsk/trunk/src/com/sun/jini/reggie/RegistrarImpl.java
Modified: river/jtsk/trunk/src/com/sun/jini/reggie/RegistrarImpl.java
URL: http://svn.apache.org/viewvc/river/jtsk/trunk/src/com/sun/jini/reggie/RegistrarImpl.java?rev=1411564&r1=1411563&r2=1411564&view=diff
==============================================================================
--- river/jtsk/trunk/src/com/sun/jini/reggie/RegistrarImpl.java (original)
+++ river/jtsk/trunk/src/com/sun/jini/reggie/RegistrarImpl.java Tue Nov 20 06:57:58 2012
@@ -83,6 +83,7 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
+import java.util.SortedMap;
import javax.net.ServerSocketFactory;
import javax.net.SocketFactory;
import javax.security.auth.Subject;
@@ -175,46 +176,49 @@ class RegistrarImpl implements Registrar
private static final EntryRep[] emptyAttrs = {};
/** Proxy for myself */
- private RegistrarProxy proxy;
+ private volatile RegistrarProxy proxy;
/** Exporter for myself */
- private Exporter serverExporter;
+ private volatile Exporter serverExporter;
/** Remote reference for myself */
- private Registrar myRef;
+ private volatile Registrar myRef;
/** Our service ID */
- private ServiceID myServiceID;
+ private volatile ServiceID myServiceID;
/** Our activation id, or null if not activatable */
- private ActivationID activationID;
+ private volatile ActivationID activationID;
/** Associated activation system, or null if not activatable */
- private ActivationSystem activationSystem;
+ private volatile ActivationSystem activationSystem;
/** Our LookupLocator */
private volatile LookupLocator myLocator;
/** Our login context, for logging out */
- private LoginContext loginContext;
+ private volatile LoginContext loginContext;
/** Shutdown callback object, or null if no callback needed */
- private LifeCycle lifeCycle;
+ private volatile LifeCycle lifeCycle;
/** Unicast socket factories */
- private ServerSocketFactory serverSocketFactory ;
- private SocketFactory socketFactory;
+ private volatile ServerSocketFactory serverSocketFactory ;
+ private volatile SocketFactory socketFactory;
/**
* Map from ServiceID to SvcReg. Every service is in this map under
* its serviceID.
*/
- private final HashMap serviceByID = new HashMap();
+ private final Map<ServiceID,SvcReg> serviceByID
+ = Collections.synchronizedMap(new HashMap<ServiceID,SvcReg>());
/**
* Identity map from SvcReg to SvcReg, ordered by lease expiration.
* Every service is in this map.
*/
- private final TreeMap serviceByTime = new TreeMap();
+ private final SortedMap<SvcReg,SvcReg> serviceByTime
+ = Collections.synchronizedSortedMap(new TreeMap<SvcReg,SvcReg>());
/**
* Map from String to HashMap mapping ServiceID to SvcReg. Every service
* is in this map under its types.
*/
- private final HashMap serviceByTypeName = new HashMap();
+ private final Map<String,Map<ServiceID,SvcReg>> serviceByTypeName
+ = Collections.synchronizedMap(new HashMap<String,Map<ServiceID,SvcReg>>());
/**
- * Map from EntryClass to HashMap[] where each HashMap is a map from
- * Object (field value) to ArrayList(SvcReg). The HashMap array has as
+ * Map from EntryClass to Map[] where each Map is a map from
+ * Object (field value) to List(SvcReg). The Map array has as
* many elements as the EntryClass has fields (including fields defined
* by superclasses). Services are in this map multiple times, once
* for each field of each entry it has. The outer map is indexed by the
@@ -223,89 +227,99 @@ class RegistrarImpl implements Registrar
* this is a small memory hit and is simpler than subtracting off base
* index values when accessing the arrays.
*/
- private final HashMap serviceByAttr = new HashMap(23);
+ private final Map<EntryClass,Map<Object,List<SvcReg>>[]> serviceByAttr
+ = Collections.synchronizedMap(new HashMap<EntryClass,Map<Object,List<SvcReg>>[]>(23));
/**
* Map from EntryClass to ArrayList(SvcReg). Services are in this map
* multiple times, once for each no-fields entry it has (no fields meaning
* none of the superclasses have fields either). The map is indexed by
* the exact type of the entry.
*/
- private final HashMap serviceByEmptyAttr = new HashMap(11);
+ private final Map<EntryClass,List<SvcReg>> serviceByEmptyAttr
+ = Collections.synchronizedMap(new HashMap<EntryClass,List<SvcReg>>(11));
/** All EntryClasses with non-zero numInstances */
- private final ArrayList entryClasses = new ArrayList();
+ private final List<EntryClass> entryClasses
+ = Collections.synchronizedList(new ArrayList<EntryClass>());
/**
* Map from Long(eventID) to EventReg. Every event registration is in
* this map under its eventID.
*/
- private final HashMap eventByID = new HashMap(11);
+ private final Map<Long,EventReg> eventByID
+ = Collections.synchronizedMap(new HashMap<Long,EventReg>(11));
/**
* Identity map from EventReg to EventReg, ordered by lease expiration.
* Every event registration is in this map.
*/
- private final TreeMap eventByTime = new TreeMap();
+ private final SortedMap<EventReg,EventReg> eventByTime
+ = Collections.synchronizedSortedMap(new TreeMap<EventReg,EventReg>());
/**
* Map from ServiceID to EventReg or EventReg[]. An event
* registration is in this map if its template matches on (at least)
* a specific serviceID.
*/
- private final HashMap subEventByService = new HashMap(11);
+ @SuppressWarnings("unchecked")
+ private final Map subEventByService = Collections.synchronizedMap(new HashMap(11));
/**
* Map from Long(eventID) to EventReg. An event registration is in
* this map if its template matches on ANY_SERVICE_ID.
*/
- private final HashMap subEventByID = new HashMap(11);
+ private final Map<Long,EventReg> subEventByID = Collections.synchronizedMap(new HashMap<Long,EventReg>(11));
/** Generator for resource (e.g., registration, lease) Uuids */
- private UuidGenerator resourceIdGenerator = new UuidGenerator();
+ private volatile UuidGenerator resourceIdGenerator = new UuidGenerator();
/** Generator for service IDs */
- private UuidGenerator serviceIdGenerator = resourceIdGenerator;
+ private volatile UuidGenerator serviceIdGenerator = resourceIdGenerator;
/** Event ID */
- private long eventID = 0;
+ private volatile long eventID = 0;
/** Random number generator for use in lookup */
private final Random random = new Random();
/** Preparer for received remote event listeners */
- private ProxyPreparer listenerPreparer = new BasicProxyPreparer();
+ private volatile ProxyPreparer listenerPreparer = new BasicProxyPreparer();
/** Preparer for remote event listeners recovered from state log */
- private ProxyPreparer recoveredListenerPreparer = listenerPreparer;
+ private volatile ProxyPreparer recoveredListenerPreparer = listenerPreparer;
/** Preparer for received lookup locators */
- private ProxyPreparer locatorPreparer = listenerPreparer;
+ private volatile ProxyPreparer locatorPreparer = listenerPreparer;
/** Preparer for lookup locators recovered from state log */
- private ProxyPreparer recoveredLocatorPreparer = listenerPreparer;
+ private volatile ProxyPreparer recoveredLocatorPreparer = listenerPreparer;
/** ArrayList of pending EventTasks */
- private final ArrayList newNotifies = new ArrayList();
+ private final List<EventTask> newNotifies = Collections.synchronizedList(new ArrayList<EventTask>());
/** Current maximum service lease duration granted, in milliseconds. */
- private long maxServiceLease;
+ private volatile long maxServiceLease;
/** Current maximum event lease duration granted, in milliseconds. */
- private long maxEventLease;
+ private volatile long maxEventLease;
/** Earliest expiration time of a SvcReg */
- private long minSvcExpiration = Long.MAX_VALUE;
+ private volatile long minSvcExpiration = Long.MAX_VALUE;
/** Earliest expiration time of an EventReg */
- private long minEventExpiration = Long.MAX_VALUE;
+ private volatile long minEventExpiration = Long.MAX_VALUE;
/** Manager for discovering other lookup services */
- private DiscoveryManagement discoer;
+ private volatile DiscoveryManagement discoer;
/** Manager for joining other lookup services */
- private JoinManager joiner;
+ private volatile JoinManager joiner;
/** Task manager for sending events and discovery responses */
- private TaskManager tasker;
+ private volatile TaskManager tasker;
/** Service lease expiration thread */
- private Thread serviceExpirer;
+ private final Thread serviceExpirer;
/** Event lease expiration thread */
- private Thread eventExpirer;
+ private final Thread eventExpirer;
/** Unicast discovery request packet receiving thread */
- private UnicastThread unicaster;
+ private volatile UnicastThread unicaster;
/** Multicast discovery request packet receiving thread */
- private Thread multicaster;
+ private final Thread multicaster;
/** Multicast discovery announcement sending thread */
- private Thread announcer;
+ private final Thread announcer;
/** Snapshot-taking thread */
- private Thread snapshotter;
+ private final Thread snapshotter;
/** Concurrent object to control read and write access */
private final ReadersWriter concurrentObj = new ReadersWriter();
+ /** TODO replace ReadersWriter.
+// private final ReadWriteLock rwlock = new ReentrantReadWriteLock();
+// private final Lock wlock = rwlock.writeLock();
+// private final Lock rlock = rwlock.readLock();
/** Object for synchronizing with the service expire thread */
private final Object serviceNotifier = new Object();
/** Object for synchronizing with the event expire thread */
@@ -314,66 +328,67 @@ class RegistrarImpl implements Registrar
private final Object snapshotNotifier = new Object();
/** Canonical ServiceType for java.lang.Object */
- private ServiceType objectServiceType;
+ private volatile ServiceType objectServiceType;
/** Log for recovering/storing state, or null if running as transient */
- private ReliableLog log;
+ private volatile ReliableLog log;
/** Flag indicating whether system is in a state of recovery */
- private boolean inRecovery;
+ private volatile boolean inRecovery;
/** Flag indicating whether system state was recovered from a snapshot */
- private boolean recoveredSnapshot = false;
+ private volatile boolean recoveredSnapshot = false;
/** Current number of records in the Log File since the last snapshot */
- private int logFileSize = 0;
+ private volatile int logFileSize = 0;
/** Log file must contain this many records before snapshot allowed */
- private int persistenceSnapshotThreshold = 200;
+ private volatile int persistenceSnapshotThreshold = 200;
/** Weight factor applied to snapshotSize when deciding to take snapshot */
- private float persistenceSnapshotWeight = 10;
+ private volatile float persistenceSnapshotWeight = 10;
/** Minimum value for maxServiceLease. */
- private long minMaxServiceLease = 1000 * 60 * 5;
+ private volatile long minMaxServiceLease = 1000 * 60 * 5;
/** Minimum value for maxEventLease. */
- private long minMaxEventLease = 1000 * 60 * 30;
+ private volatile long minMaxEventLease = 1000 * 60 * 30;
/** Minimum average time between lease renewals, in milliseconds. */
- private long minRenewalInterval = 100;
+ private volatile long minRenewalInterval = 100;
/** Port for unicast discovery */
- private int unicastPort = 0;
+ private volatile int unicastPort = 0;
/** The groups we are a member of */
private volatile String[] memberGroups = { "" };
/** The groups we should join */
- private String[] lookupGroups = DiscoveryGroupManagement.NO_GROUPS;
+ private volatile String[] lookupGroups = DiscoveryGroupManagement.NO_GROUPS;
/** The locators of other lookups we should join */
- private LookupLocator[] lookupLocators = {};
+ private volatile LookupLocator[] lookupLocators = {};
/** The attributes to use when joining (including with myself) */
- private Entry[] lookupAttrs;
+ private volatile Entry[] lookupAttrs;
/** Interval to wait in between sending multicast announcements */
- private long multicastAnnouncementInterval = 1000 * 60 * 2;
+ private volatile long multicastAnnouncementInterval = 1000 * 60 * 2;
/** Multicast announcement sequence number */
private volatile long announcementSeqNo = 0L;
/** Network interfaces to use for multicast discovery */
- private NetworkInterface[] multicastInterfaces;
+ /** shared among threads, but not mutated after construction */
+ private volatile NetworkInterface[] multicastInterfaces;
/** Flag indicating whether network interfaces were explicitly specified */
- private boolean multicastInterfacesSpecified;
+ private volatile boolean multicastInterfacesSpecified;
/** Interval to wait in between retrying failed interfaces */
- private int multicastInterfaceRetryInterval = 1000 * 60 * 5;
+ private volatile int multicastInterfaceRetryInterval = 1000 * 60 * 5;
/** Utility for participating in version 2 of discovery protocols */
- private Discovery protocol2;
+ private volatile Discovery protocol2;
/** Cached raw constraints associated with unicastDiscovery method*/
- private InvocationConstraints rawUnicastDiscoveryConstraints;
+ private volatile InvocationConstraints rawUnicastDiscoveryConstraints;
/** Constraints specified for incoming multicast requests */
- private DiscoveryConstraints multicastRequestConstraints;
+ private volatile DiscoveryConstraints multicastRequestConstraints;
/** Constraints specified for outgoing multicast announcements */
- private DiscoveryConstraints multicastAnnouncementConstraints;
+ private volatile DiscoveryConstraints multicastAnnouncementConstraints;
/** Constraints specified for handling unicast discovery */
- private DiscoveryConstraints unicastDiscoveryConstraints;
+ private volatile DiscoveryConstraints unicastDiscoveryConstraints;
/** Client subject checker to apply to incoming multicast requests */
- private ClientSubjectChecker multicastRequestSubjectChecker;
+ private volatile ClientSubjectChecker multicastRequestSubjectChecker;
/** Maximum time to wait for calls to finish before forcing unexport */
private volatile long unexportTimeout = 1000 * 60 * 2;
/** Time to wait between unexport attempts */
private volatile long unexportWait = 1000;
/** Client subject checker to apply to unicast discovery attempts */
- private ClientSubjectChecker unicastDiscoverySubjectChecker;
+ private volatile ClientSubjectChecker unicastDiscoverySubjectChecker;
/** Lock protecting startup and shutdown */
private final ReadyState ready = new ReadyState();
@@ -397,6 +412,16 @@ class RegistrarImpl implements Registrar
configArgs, getClass().getClassLoader());
loginAndRun(config,activationID,persistent,lifeCycle);
+ serviceExpirer = new ServiceExpireThread();
+ eventExpirer = new EventExpireThread();
+ multicaster = new MulticastThread();
+ announcer = new AnnounceThread();
+ snapshotter = new SnapshotThread();
+ serviceExpirer.start();
+ eventExpirer.start();
+ multicaster.start();
+ announcer.start();
+ snapshotter.start();
} catch (Throwable t) {
logger.log(Level.SEVERE, "Reggie initialization failed", t);
if (t instanceof Exception) {
@@ -423,6 +448,16 @@ class RegistrarImpl implements Registrar
{
try {
loginAndRun(config,activationID,persistent,lifeCycle);
+ serviceExpirer = new ServiceExpireThread();
+ eventExpirer = new EventExpireThread();
+ multicaster = new MulticastThread();
+ announcer = new AnnounceThread();
+ snapshotter = new SnapshotThread();
+ serviceExpirer.start();
+ eventExpirer.start();
+ multicaster.start();
+ announcer.start();
+ snapshotter.start();
} catch (Throwable t) {
logger.log(Level.SEVERE, "Reggie initialization failed", t);
if (t instanceof Exception) {
@@ -707,7 +742,7 @@ class RegistrarImpl implements Registrar
*/
public void apply(RegistrarImpl regImpl) {
SvcReg oldReg =
- (SvcReg)regImpl.serviceByID.get(reg.item.serviceID);
+ (SvcReg)regImpl.serviceByID.get(reg.item.serviceID);
if (oldReg != null)
regImpl.deleteService(oldReg, 0);
regImpl.addService(reg);
@@ -1239,7 +1274,7 @@ class RegistrarImpl implements Registrar
*
* @serial
*/
- private int newPort;
+ private final int newPort;
/** Simple constructor */
public UnicastPortSetLogObj(int newPort) {
@@ -1272,7 +1307,7 @@ class RegistrarImpl implements Registrar
*
* @serial
*/
- private String[] groups;
+ private final String[] groups;
/** Simple constructor */
public LookupGroupsChangedLogObj(String[] groups) {
@@ -1362,7 +1397,7 @@ class RegistrarImpl implements Registrar
*
* @serial
*/
- private String[] groups;
+ private final String[] groups;
/** Simple constructor */
public MemberGroupsChangedLogObj(String[] groups) {
@@ -1558,7 +1593,10 @@ class RegistrarImpl implements Registrar
}
}
- /** Base class for iterating over all Items that match a Template. */
+ /** Base class for iterating over all Items that match a Template.
+ * ItemIter are for single threaded use, however they access collections
+ * that may be accessed by other threads */
+
private abstract class ItemIter {
/** Current time */
public final long now = System.currentTimeMillis();
@@ -1604,7 +1642,7 @@ class RegistrarImpl implements Registrar
/** Iterate over all Items. */
private class AllItemIter extends ItemIter {
/** Iterator over serviceByID */
- private final Iterator iter;
+ private final Iterator<SvcReg> iter;
/** Assumes the empty template */
public AllItemIter() {
@@ -1614,12 +1652,14 @@ class RegistrarImpl implements Registrar
}
/** Set reg to the next matching element, or null if none */
- protected void step() {
- while (iter.hasNext()) {
- reg = (SvcReg)iter.next();
- if (reg.leaseExpiration > now)
- return;
- }
+ protected final void step() {
+ synchronized (serviceByID){
+ while (iter.hasNext()) {
+ reg = iter.next();
+ if (reg.leaseExpiration > now)
+ return;
+ }
+ }
reg = null;
}
}
@@ -1627,49 +1667,65 @@ class RegistrarImpl implements Registrar
/** Iterates over all services that match template's service types */
private class SvcIterator extends ItemIter {
/** Iterator for list of matching services. */
- private final Iterator services;
+ private final Iterator<SvcReg> services;
+ private final Map<ServiceID,SvcReg> mutex;
/**
* tmpl.serviceID == null and
* tmpl.serviceTypes is not empty
*/
+ @SuppressWarnings("unchecked")
public SvcIterator(Template tmpl) {
super(tmpl);
- Map map = (Map) serviceByTypeName.get(
+ Map<ServiceID,SvcReg> map = serviceByTypeName.get(
tmpl.serviceTypes[0].getName());
- services = map != null ? map.values().iterator() :
- Collections.EMPTY_LIST.iterator();
+ mutex = (Map<ServiceID, SvcReg>) (map != null ? map : Collections.emptyMap());
+ services = mutex.values().iterator();
step();
}
/** Set reg to the next matching element, or null if none. */
- protected void step() {
+ protected final void step() {
if (tmpl.serviceTypes.length > 1) {
- while (services.hasNext()) {
- reg = (SvcReg) services.next();
- if (reg.leaseExpiration > now &&
- matchType(tmpl.serviceTypes, reg.item.serviceType) &&
- matchAttributes(tmpl, reg.item))
- return;
- }
+ synchronized (mutex){
+ while (services.hasNext()) {
+ reg = services.next();
+ if (reg.leaseExpiration > now &&
+ matchType(tmpl.serviceTypes, reg.item.serviceType) &&
+ matchAttributes(tmpl, reg.item))
+ return;
+ }
+ }
} else {
- while (services.hasNext()) {
- reg = (SvcReg) services.next();
- if (reg.leaseExpiration > now &&
- matchAttributes(tmpl, reg.item))
- return;
- }
+ synchronized (mutex){
+ while (services.hasNext()) {
+ reg = (SvcReg) services.next();
+ if (reg.leaseExpiration > now &&
+ matchAttributes(tmpl, reg.item))
+ return;
+ }
+ }
}
reg = null;
}
}
-
/** Iterate over all matching Items by attribute value. */
private class AttrItemIter extends ItemIter {
/** SvcRegs obtained from serviceByAttr for chosen attr */
- protected ArrayList svcs;
+ protected final List<SvcReg> svcs;
/** Current index into svcs */
- protected int svcidx;
+ protected int svcidx = 0;
+
+ protected AttrItemIter(Template tmpl, List<SvcReg> svcs){
+ super(tmpl);
+ if (svcs != null) {
+ svcidx = svcs.size();
+ this.svcs = svcs;
+ step();
+ } else {
+ this.svcs = Collections.emptyList();
+ }
+ }
/**
* tmpl.serviceID == null and
@@ -1679,27 +1735,33 @@ class RegistrarImpl implements Registrar
public AttrItemIter(Template tmpl, int setidx, int fldidx) {
super(tmpl);
EntryRep set = tmpl.attributeSetTemplates[setidx];
- HashMap[] attrMaps =
- (HashMap[])serviceByAttr.get(getDefiningClass(set.eclass,
+ Map<Object,List<SvcReg>>[] attrMaps =
+ serviceByAttr.get(getDefiningClass(set.eclass,
fldidx));
+ List<SvcReg> svcs = null;
if (attrMaps != null && attrMaps[fldidx] != null) {
- svcs = (ArrayList)attrMaps[fldidx].get(set.fields[fldidx]);
+ svcs = attrMaps[fldidx].get(set.fields[fldidx]);
if (svcs != null) {
svcidx = svcs.size();
+ this.svcs = svcs;
step();
- }
- }
+ } else {
+ this.svcs = Collections.emptyList();
+ }
+ } else {
+ this.svcs = Collections.emptyList();
+ }
}
/** Simple constructor */
protected AttrItemIter(Template tmpl) {
- super(tmpl);
+ this(tmpl, null);
}
/** Set reg to the next matching element, or null if none. */
- protected void step() {
+ protected final void step() {
while (--svcidx >= 0) {
- reg = (SvcReg)svcs.get(svcidx);
+ reg = svcs.get(svcidx);
if (reg.leaseExpiration > now &&
matchAttributes(tmpl, reg.item))
return;
@@ -1717,8 +1779,7 @@ class RegistrarImpl implements Registrar
* eclass has no fields
*/
public EmptyAttrItemIter(Template tmpl, EntryClass eclass) {
- super(tmpl);
- svcs = (ArrayList)serviceByEmptyAttr.get(eclass);
+ super(tmpl,serviceByEmptyAttr.get(eclass) );
if (svcs != null) {
svcidx = svcs.size();
step();
@@ -1733,9 +1794,10 @@ class RegistrarImpl implements Registrar
/** Current index into entryClasses */
private int classidx;
/** Values iterator for current HashMap */
- private Iterator iter;
+ private Iterator<List<SvcReg>> iter;
+ private Object mutex;
/** SvcRegs obtained from iter or serviceByEmptyAttr */
- private ArrayList svcs;
+ private List<SvcReg> svcs;
/** Current index into svcs */
private int svcidx = 0;
@@ -1749,14 +1811,15 @@ class RegistrarImpl implements Registrar
dupsPossible = true;
eclass = tmpl.attributeSetTemplates[0].eclass;
classidx = entryClasses.size();
+ mutex = new Object();
step();
}
/** Set reg to the next matching element, or null if none */
- protected void step() {
+ protected final void step() {
do {
while (--svcidx >= 0) {
- reg = (SvcReg)svcs.get(svcidx);
+ reg = svcs.get(svcidx);
if (reg.leaseExpiration > now &&
matchAttributes(tmpl, reg.item))
return;
@@ -1771,11 +1834,13 @@ class RegistrarImpl implements Registrar
*/
private boolean stepValue() {
while (true) {
- if (iter != null && iter.hasNext()) {
- svcs = (ArrayList)iter.next();
- svcidx = svcs.size();
- return true;
- }
+ synchronized (mutex){ //REMIND: Locking not satisfactory during iteration.
+ if (iter != null && iter.hasNext()) {
+ svcs = iter.next();
+ svcidx = svcs.size();
+ return true;
+ }
+ }
if (!stepClass())
return false;
if (iter == null)
@@ -1791,16 +1856,19 @@ class RegistrarImpl implements Registrar
*/
private boolean stepClass() {
while (--classidx >= 0) {
- EntryClass cand = (EntryClass)entryClasses.get(classidx);
+ EntryClass cand = entryClasses.get(classidx);
if (!eclass.isAssignableFrom(cand))
continue;
if (cand.getNumFields() > 0) {
cand = getDefiningClass(cand, cand.getNumFields() - 1);
- HashMap[] attrMaps = (HashMap[])serviceByAttr.get(cand);
- iter = attrMaps[attrMaps.length - 1].values().iterator();
+ Map<Object,List<SvcReg>>[] attrMaps = serviceByAttr.get(cand);
+ Map<Object,List<SvcReg>> mutex = attrMaps[attrMaps.length - 1];
+ this.mutex = mutex;
+ iter = mutex.values().iterator();
} else {
iter = null;
- svcs = (ArrayList)serviceByEmptyAttr.get(cand);
+ mutex = new Object();
+ svcs = serviceByEmptyAttr.get(cand);
svcidx = svcs.size();
}
return true;
@@ -1815,7 +1883,7 @@ class RegistrarImpl implements Registrar
/** tmpl.serviceID != null */
public IDItemIter(Template tmpl) {
super(tmpl);
- reg = (SvcReg)serviceByID.get(tmpl.serviceID);
+ reg = serviceByID.get(tmpl.serviceID);
if (reg != null &&
(reg.leaseExpiration <= now || !matchItem(tmpl, reg.item)))
reg = null;
@@ -2207,7 +2275,7 @@ class RegistrarImpl implements Registrar
long now = System.currentTimeMillis();
minEventExpiration = Long.MAX_VALUE;
while (!eventByTime.isEmpty()) {
- EventReg reg = (EventReg)eventByTime.firstKey();
+ EventReg reg = (EventReg) eventByTime.firstKey();
if (reg.leaseExpiration > now) {
minEventExpiration = reg.leaseExpiration;
break;
@@ -3651,9 +3719,9 @@ class RegistrarImpl implements Registrar
/** Adds a service registration to types in its hierarchy */
private void addServiceByTypes(ServiceType type, SvcReg reg) {
- Map map = (Map) serviceByTypeName.get(type.getName());
+ Map<ServiceID,SvcReg> map = serviceByTypeName.get(type.getName());
if (map == null) {
- map = new HashMap();
+ map = Collections.synchronizedMap(new HashMap<ServiceID,SvcReg>());
serviceByTypeName.put(type.getName(), map);
}
map.put(reg.item.serviceID, reg);
@@ -3669,7 +3737,7 @@ class RegistrarImpl implements Registrar
/** Deletes a service registration from types in its hierarchy */
private void deleteServiceFromTypes(ServiceType type, SvcReg reg)
{
- Map map = (Map) serviceByTypeName.get(type.getName());
+ Map<ServiceID,SvcReg> map = serviceByTypeName.get(type.getName());
if (map != null) {
map.remove(reg.item.serviceID);
if ((map.isEmpty()) && !type.equals(objectServiceType))
@@ -4115,14 +4183,16 @@ class RegistrarImpl implements Registrar
}
return;
}
- ArrayList regs = (ArrayList)serviceByEmptyAttr.get(eclass);
- if (regs == null) {
- regs = new ArrayList(2);
- regs.add(reg);
- serviceByEmptyAttr.put(eclass, regs);
- } else if (!regs.contains(reg)) {
- regs.add(reg);
- }
+ synchronized (serviceByEmptyAttr){
+ List<SvcReg> regs = serviceByEmptyAttr.get(eclass);
+ if (regs == null) {
+ regs = Collections.synchronizedList(new ArrayList<SvcReg>(2));
+ regs.add(reg);
+ serviceByEmptyAttr.put(eclass, regs);
+ } else if (!regs.contains(reg)) {
+ regs.add(reg);
+ }
+ }
}
/**
@@ -4139,42 +4209,46 @@ class RegistrarImpl implements Registrar
deleteInstance(eclass);
Object[] fields = entry.fields;
if (fields.length == 0) {
- ArrayList regs = (ArrayList)serviceByEmptyAttr.get(eclass);
- if (regs == null || (checkDups && hasEmptyAttr(reg, eclass)))
- return;
- int idx = regs.indexOf(reg);
- if (idx >= 0) {
- regs.remove(idx);
- if (regs.isEmpty())
- serviceByEmptyAttr.remove(eclass);
- }
- return;
+ List<SvcReg> regs = serviceByEmptyAttr.get(eclass);
+ if (regs == null || (checkDups && hasEmptyAttr(reg, eclass)))
+ return;
+ int idx = regs.indexOf(reg);
+ if (idx >= 0) {
+ synchronized (serviceByEmptyAttr){
+ regs.remove(idx);
+ if (regs.isEmpty())
+ serviceByEmptyAttr.remove(eclass);
+ }
+ }
+ return;
}
/* walk backwards to make getDefiningClass more efficient */
for (int fldidx = fields.length; --fldidx >= 0; ) {
eclass = getDefiningClass(eclass, fldidx);
- HashMap[] attrMaps = (HashMap[])serviceByAttr.get(eclass);
- if (attrMaps == null ||
- attrMaps[fldidx] == null ||
- (checkDups && hasAttr(reg, eclass, fldidx, fields[fldidx])))
- continue;
- HashMap map = attrMaps[fldidx];
- Object value = fields[fldidx];
- ArrayList regs = (ArrayList)map.get(value);
- if (regs == null)
- continue;
- int idx = regs.indexOf(reg);
- if (idx < 0)
- continue;
- regs.remove(idx);
- if (!regs.isEmpty())
- continue;
- map.remove(value);
- if (!map.isEmpty())
- continue;
- attrMaps[fldidx] = null;
- if (allNull(attrMaps))
- serviceByAttr.remove(eclass);
+ synchronized (serviceByAttr){
+ Map<Object,List<SvcReg>>[] attrMaps = serviceByAttr.get(eclass);
+ if (attrMaps == null ||
+ attrMaps[fldidx] == null ||
+ (checkDups && hasAttr(reg, eclass, fldidx, fields[fldidx])))
+ continue;
+ Map<Object,List<SvcReg>> map = attrMaps[fldidx];
+ Object value = fields[fldidx];
+ List<SvcReg> regs = map.get(value);
+ if (regs == null)
+ continue;
+ int idx = regs.indexOf(reg);
+ if (idx < 0)
+ continue;
+ regs.remove(idx);
+ if (!regs.isEmpty())
+ continue;
+ map.remove(value);
+ if (!map.isEmpty())
+ continue;
+ attrMaps[fldidx] = null;
+ if (allNull(attrMaps))
+ serviceByAttr.remove(eclass);
+ }
}
}
@@ -4191,14 +4265,16 @@ class RegistrarImpl implements Registrar
Object nval = values[fldidx];
if (nval != null && !nval.equals(oval)) {
eclass = getDefiningClass(eclass, fldidx);
- HashMap map = addAttr(reg, eclass, fldidx, nval);
+ Map<Object,List<SvcReg>> map = addAttr(reg, eclass, fldidx, nval);
entry.fields[fldidx] = nval;
if (hasAttr(reg, eclass, fldidx, oval))
continue;
- ArrayList regs = (ArrayList)map.get(oval);
- regs.remove(regs.indexOf(reg));
- if (regs.isEmpty())
- map.remove(oval); /* map cannot become empty */
+ synchronized (serviceByAttr){
+ List<SvcReg> regs = map.get(oval);
+ regs.remove(regs.indexOf(reg));
+ if (regs.isEmpty())
+ map.remove(oval); /* map cannot become empty */
+ }
}
}
}
@@ -4208,29 +4284,32 @@ class RegistrarImpl implements Registrar
* defining class and field, if it isn't already there. Return
* the HashMap for the given class and field.
*/
- private HashMap addAttr(SvcReg reg,
+ @SuppressWarnings("unchecked")
+ private Map<Object,List<SvcReg>> addAttr(SvcReg reg,
EntryClass eclass,
int fldidx,
Object value)
{
- HashMap[] attrMaps = (HashMap[])serviceByAttr.get(eclass);
- if (attrMaps == null) {
- attrMaps = new HashMap[eclass.getNumFields()];
- serviceByAttr.put(eclass, attrMaps);
- }
- HashMap map = attrMaps[fldidx];
- if (map == null) {
- map = new HashMap(11);
- attrMaps[fldidx] = map;
- }
- ArrayList regs = (ArrayList)map.get(value);
- if (regs == null) {
- regs = new ArrayList(3);
- map.put(value, regs);
- } else if (regs.contains(reg))
- return map;
- regs.add(reg);
- return map;
+ synchronized (serviceByAttr){
+ Map<Object,List<SvcReg>>[] attrMaps = serviceByAttr.get(eclass);
+ if (attrMaps == null) {
+ attrMaps = new Map[eclass.getNumFields()];
+ serviceByAttr.put(eclass, attrMaps);
+ }
+ Map<Object,List<SvcReg>> map = attrMaps[fldidx];
+ if (map == null) {
+ map = Collections.synchronizedMap(new HashMap<Object,List<SvcReg>>(11));
+ attrMaps[fldidx] = map;
+ }
+ List<SvcReg> regs = map.get(value);
+ if (regs == null) {
+ regs = Collections.synchronizedList(new ArrayList<SvcReg>(3));
+ map.put(value, regs);
+ } else if (regs.contains(reg))
+ return map;
+ regs.add(reg);
+ return map;
+ }
}
/**
@@ -4243,7 +4322,7 @@ class RegistrarImpl implements Registrar
entryClasses.add(eclass);
idx = entryClasses.size() - 1;
}
- eclass = (EntryClass) entryClasses.get(idx);
+ eclass = entryClasses.get(idx);
eclass.setNumInstances(eclass.getNumInstances() + 1);
}
@@ -4294,7 +4373,7 @@ class RegistrarImpl implements Registrar
private EntryClass getEmptyEntryClass(EntryClass eclass) {
EntryClass match = null;
for (int i = entryClasses.size(); --i >= 0; ) {
- EntryClass cand = (EntryClass)entryClasses.get(i);
+ EntryClass cand = entryClasses.get(i);
if (eclass.isAssignableFrom(cand)) {
if (cand.getNumFields() != 0 || match != null)
return null;
@@ -4305,18 +4384,18 @@ class RegistrarImpl implements Registrar
}
/** Returns a list of services that match all types passed in */
- private ArrayList matchingServices(ServiceType[] types) {
- ArrayList matches = new ArrayList();
+ private List<SvcReg> matchingServices(ServiceType[] types) {
+ List<SvcReg> matches = new ArrayList<SvcReg>();
if (isEmpty(types)) {
- Map map = (Map) serviceByTypeName.get(objectServiceType.getName());
+ Map<ServiceID,SvcReg> map = serviceByTypeName.get(objectServiceType.getName());
matches.addAll(map.values());
} else {
- Map map = (Map) serviceByTypeName.get(types[0].getName());
+ Map<ServiceID,SvcReg> map = serviceByTypeName.get(types[0].getName());
if (map != null)
matches.addAll(map.values());
if (types.length > 1) {
- for (Iterator it = matches.iterator(); it.hasNext(); ) {
- SvcReg reg = (SvcReg) it.next();
+ for (Iterator<SvcReg> it = matches.iterator(); it.hasNext(); ) {
+ SvcReg reg = it.next();
if (!matchType(types, reg.item.serviceType))
it.remove();
}
@@ -4331,28 +4410,30 @@ class RegistrarImpl implements Registrar
{
if (eclass.getNumFields() == 0)
return pickCodebase(eclass,
- (ArrayList)serviceByEmptyAttr.get(eclass),
+ serviceByEmptyAttr.get(eclass),
now);
int fldidx = eclass.getNumFields() - 1;
- HashMap[] attrMaps =
- (HashMap[])serviceByAttr.get(getDefiningClass(eclass, fldidx));
- for (Iterator iter = attrMaps[fldidx].values().iterator();
- iter.hasNext(); )
- {
- try {
- return pickCodebase(eclass, (ArrayList)iter.next(), now);
- } catch (ClassNotFoundException e) {
- }
- }
- throw new ClassNotFoundException();
+ Map<Object,List<SvcReg>>[] attrMaps =
+ serviceByAttr.get(getDefiningClass(eclass, fldidx));
+ synchronized (attrMaps[fldidx]){
+ for (Iterator<List<SvcReg>> iter = attrMaps[fldidx].values().iterator();
+ iter.hasNext(); )
+ {
+ try {
+ return pickCodebase(eclass, iter.next(), now);
+ } catch (ClassNotFoundException e) {
+ }
+ }
+ throw new ClassNotFoundException();
+ }
}
/** Return any valid codebase for an entry of the exact given class. */
- private String pickCodebase(EntryClass eclass, ArrayList svcs, long now)
+ private String pickCodebase(EntryClass eclass, List<SvcReg> svcs, long now)
throws ClassNotFoundException
{
for (int i = svcs.size(); --i >= 0; ) {
- SvcReg reg = (SvcReg)svcs.get(i);
+ SvcReg reg = svcs.get(i);
if (reg.leaseExpiration <= now)
continue;
EntryRep[] sets = reg.item.attributeSets;
@@ -4684,12 +4765,7 @@ class RegistrarImpl implements Registrar
DiscoveryConstraints.multicastAnnouncementMethod));
unicastDiscoveryConstraints = DiscoveryConstraints.process(
rawUnicastDiscoveryConstraints);
- serviceExpirer = new ServiceExpireThread();
- eventExpirer = new EventExpireThread();
unicaster = new UnicastThread(unicastPort);
- multicaster = new MulticastThread();
- announcer = new AnnounceThread();
- snapshotter = new SnapshotThread();
if (myServiceID == null) {
myServiceID = newServiceID();
}
@@ -4733,11 +4809,7 @@ class RegistrarImpl implements Registrar
discoer, null, config);
/* start up all the daemon threads */
- serviceExpirer.start();
- eventExpirer.start();
unicaster.start();
- multicaster.start();
- announcer.start();
/* Shutdown hook so reggie sends a final announcement
* packet if VM is terminated. If reggie is terminated
@@ -4758,7 +4830,6 @@ class RegistrarImpl implements Registrar
}
}));
- snapshotter.start();
if (logger.isLoggable(Level.INFO)) {
logger.log(Level.INFO, "started Reggie: {0}, {1}, {2}",
new Object[]{ myServiceID,
@@ -4768,7 +4839,8 @@ class RegistrarImpl implements Registrar
ready.ready();
}
- /** The code that does the real work of register. */
+ /** The code that does the real work of register.
+ * called while holding concurrentObj.writeLock() */
private ServiceRegistration registerDo(Item nitem, long leaseDuration)
{
if (nitem.service == null)
@@ -4783,16 +4855,18 @@ class RegistrarImpl implements Registrar
long now = System.currentTimeMillis();
if (nitem.serviceID == null) {
/* new service, match on service object */
- Map svcs = (Map)serviceByTypeName.get(nitem.serviceType.getName());
+ Map<ServiceID,SvcReg> svcs = serviceByTypeName.get(nitem.serviceType.getName());
if (svcs != null) {
- for (Iterator it = svcs.values().iterator(); it.hasNext(); ) {
- SvcReg reg = (SvcReg)it.next();
- if (nitem.service.equals(reg.item.service)) {
- nitem.serviceID = reg.item.serviceID;
- deleteService(reg, now);
- break;
- }
- }
+ synchronized (svcs){
+ for (Iterator<SvcReg> it = svcs.values().iterator(); it.hasNext(); ) {
+ SvcReg reg = it.next();
+ if (nitem.service.equals(reg.item.service)) {
+ nitem.serviceID = reg.item.serviceID;
+ deleteService(reg, now);
+ break;
+ }
+ }
+ }
}
if (nitem.serviceID == null)
nitem.serviceID = newServiceID();
@@ -5001,7 +5075,7 @@ class RegistrarImpl implements Registrar
*/
private Object[] getFieldValuesDo(Template tmpl, int setidx, int fldidx)
{
- ArrayList values = new ArrayList();
+ List<Object> values = new ArrayList<Object>();
EntryRep etmpl = tmpl.attributeSetTemplates[setidx];
if (tmpl.serviceID == null &&
isEmpty(tmpl.serviceTypes) &&
@@ -5011,24 +5085,26 @@ class RegistrarImpl implements Registrar
long now = System.currentTimeMillis();
EntryClass eclass = getDefiningClass(etmpl.eclass, fldidx);
boolean checkAttr = !eclass.equals(etmpl.eclass);
- HashMap[] attrMaps = (HashMap[])serviceByAttr.get(eclass);
+ Map<Object,List<SvcReg>>[] attrMaps = serviceByAttr.get(eclass);
if (attrMaps != null && attrMaps[fldidx] != null) {
- for (Iterator iter = attrMaps[fldidx].entrySet().iterator();
- iter.hasNext(); )
- {
- Map.Entry ent = (Map.Entry)iter.next();
- ArrayList regs = (ArrayList)ent.getValue();
- Object value = ent.getKey();
- for (int i = regs.size(); --i >= 0; ) {
- SvcReg reg = (SvcReg)regs.get(i);
- if (reg.leaseExpiration > now &&
- (!checkAttr ||
- hasAttr(reg, etmpl.eclass, fldidx, value))) {
- values.add(value);
- break;
- }
- }
- }
+ synchronized (attrMaps[fldidx]){
+ for (Iterator<Map.Entry<Object,List<SvcReg>>> iter = attrMaps[fldidx].entrySet().iterator();
+ iter.hasNext(); )
+ {
+ Map.Entry<Object,List<SvcReg>> ent = iter.next();
+ List<SvcReg> regs = ent.getValue();
+ Object value = ent.getKey();
+ for (int i = regs.size(); --i >= 0; ) {
+ SvcReg reg = regs.get(i);
+ if (reg.leaseExpiration > now &&
+ (!checkAttr ||
+ hasAttr(reg, etmpl.eclass, fldidx, value))) {
+ values.add(value);
+ break;
+ }
+ }
+ }
+ }
}
} else {
for (ItemIter iter = matchingItems(tmpl); iter.hasNext(); ) {
@@ -5582,13 +5658,15 @@ class RegistrarImpl implements Registrar
stream.writeLong(announcementSeqNo);
marshalAttributes(lookupAttrs, stream);
marshalLocators(lookupLocators, stream);
- for (Iterator iter = serviceByID.entrySet().iterator();
- iter.hasNext(); )
- {
- Map.Entry entry = (Map.Entry) iter.next();
- if (myServiceID != entry.getKey())
- stream.writeObject(entry.getValue());
- }
+ synchronized (serviceByID){
+ for (Iterator iter = serviceByID.entrySet().iterator();
+ iter.hasNext(); )
+ {
+ Map.Entry entry = (Map.Entry) iter.next();
+ if (myServiceID != entry.getKey())
+ stream.writeObject(entry.getValue());
+ }
+ }
stream.writeObject(null);
for (Iterator iter = eventByID.values().iterator(); iter.hasNext(); )
{