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(); ) {
