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 2020/07/05 11:41:42 UTC
svn commit: r1879521 [26/37] - in
/river/jtsk/modules/modularize/apache-river: ./ browser/
browser/src/main/java/org/apache/river/example/browser/ extra/
groovy-config/ river-activation/ river-collections/
river-collections/src/main/java/org/apache/riv...
Modified: river/jtsk/modules/modularize/apache-river/river-services/outrigger/outrigger-service/src/main/java/org/apache/river/outrigger/AvailabilityRegistrationWatcher.java
URL: http://svn.apache.org/viewvc/river/jtsk/modules/modularize/apache-river/river-services/outrigger/outrigger-service/src/main/java/org/apache/river/outrigger/AvailabilityRegistrationWatcher.java?rev=1879521&r1=1879520&r2=1879521&view=diff
==============================================================================
--- river/jtsk/modules/modularize/apache-river/river-services/outrigger/outrigger-service/src/main/java/org/apache/river/outrigger/AvailabilityRegistrationWatcher.java (original)
+++ river/jtsk/modules/modularize/apache-river/river-services/outrigger/outrigger-service/src/main/java/org/apache/river/outrigger/AvailabilityRegistrationWatcher.java Sun Jul 5 11:41:39 2020
@@ -1,382 +1,385 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.
- */
-package org.apache.river.outrigger;
-
-import java.io.IOException;
-import java.rmi.RemoteException;
-import java.rmi.MarshalledObject;
-import java.util.Set;
-import java.util.Iterator;
-import net.jini.core.event.RemoteEventListener;
-import net.jini.core.event.RemoteEvent;
-import net.jini.core.event.UnknownEventException;
-import net.jini.id.Uuid;
-import net.jini.security.ProxyPreparer;
-import net.jini.space.JavaSpace;
-import org.apache.river.landlord.LeasedResource;
-
-/**
- * Subclass of <code>TransitionWatcher</code> for availability event
- * registrations. Also represents the event registration itself.
- */
-abstract class AvailabilityRegistrationWatcher extends TransitionWatcher
- implements EventRegistrationRecord
-{
- /**
- * The current expiration time of the registration
- * Protected, but only for use by subclasses.
- */
- long expiration;
-
- /**
- * The UUID that identifies this registration
- * Only for use by subclasses.
- * Should not be changed.
- */
- volatile Uuid cookie;
-
- /**
- * The handback associated with this registration.
- * Only for use by subclasses.
- * Should not be changed.
- */
- MarshalledObject handback;
-
- /**
- * <code>true</code> if client is interested
- * in only visibility events, <code>false</code>
- * otherwise.
- * Only for use by subclasses.
- * Should not be changed.
- */
- volatile boolean visibilityOnly;
-
- /**
- * The event ID associated with this registration
- * Protected, but only for use by subclasses.
- * Should not be changed.
- */
- long eventID;
-
- /**
- * The current sequence number.
- */
- private long currentSeqNum = 0;
-
- /**
- * The <code>TemplateHandle</code>s associated with this
- * watcher.
- */
- private final Set<TemplateHandle> owners = new java.util.HashSet<TemplateHandle>();
- private boolean removed = false;
-
- /**
- * The OutriggerServerImpl we are part of.
- */
- private OutriggerServerImpl server;
-
- /**
- * Used during log recovery to create a mostly empty
- * <code>AvailabilityRegistrationWatcher</code>.
- * <p>
- * Note, we set the time stamp and tie-breaker here instead of
- * getting them from the log. This means they will be inconstant
- * with their value from the last VM we were in, but since they
- * never leak out and events are read-only anyway this should not
- * be a problem (this also allows us to keep the tie-breaker and
- * time stamp in final fields).
- *
- * @param timestamp the value that is used
- * to sort <code>TransitionWatcher</code>s.
- * @param startOrdinal the highest ordinal associated
- * with operations that are considered to have occurred
- * before the operation associated with this watcher.
- * @param currentSeqNum Sequence number to start with.
- */
- AvailabilityRegistrationWatcher(long timestamp, long startOrdinal,
- long currentSeqNum)
- {
- super(timestamp, startOrdinal);
- this.currentSeqNum = currentSeqNum;
- }
-
- /**
- * Create a new <code>AvailabilityRegistrationWatcher</code>.
- * @param timestamp the value that is used
- * to sort <code>TransitionWatcher</code>s.
- * @param startOrdinal the highest ordinal associated
- * with operations that are considered to have occurred
- * before the operation associated with this watcher.
- * @param cookie The unique identifier associated
- * with this watcher. Must not be <code>null</code>.
- * @param visibilityOnly pass <code>true</code> if client
- * only wants visibility events
- * @param handback The handback object that
- * should be sent along with event
- * notifications to the the listener.
- * @param eventID The event ID for event type
- * represented by this object.
- * @throws NullPointerException if the <code>cookie</code>
- * argument is <code>null</code>.
- */
- AvailabilityRegistrationWatcher(long timestamp, long startOrdinal,
- Uuid cookie, boolean visibilityOnly, MarshalledObject handback,
- long eventID)
- {
- super(timestamp, startOrdinal);
-
- if (cookie == null)
- throw new NullPointerException("cookie must be non-null");
-
- this.cookie = cookie;
- this.handback = handback;
- this.eventID = eventID;
- this.visibilityOnly = visibilityOnly;
- }
-
- /**
- * Process the given transition by queuing up a task with the
- * notifier for event delivery. Assumes the passed entry matches
- * the template in the <code>TemplateHandle</code> associated with
- * this watcher and that <code>isInterested</code> returned
- * <code>true</code>. If <code>remove</code> has been called or
- * the expiration time of this watcher has passed, this call
- * should have no effect. This call may cause the watcher to be
- * removed.
- * @param transition A <code>EntryTransition</code> that
- * describes the transition and what
- * entry is transitioning. This method
- * will assume that <code>transition.getHandle</code>
- * returns a non-null value.
- * @param now An estimate of the current time (not the time
- * when the event occurred).
- * @throws NullPointerException if <code>transition</code> is
- * <code>null</code>.
- */
- void process(EntryTransition transition, long now) {
- boolean doneFor = false;
-
- // lock before checking the time and so we can update currentSeqNum
- synchronized (this) {
- if (removed) return; // Must have been removed
-
- if (now > expiration) {
- doneFor = true;
- } else {
- server.enqueueDelivery(
- new VisibilityEventSender(
- transition.getHandle().rep(),
- transition.isVisible(),
- currentSeqNum++));
- }
- }
-
- if (doneFor) cancel();
- }
-
- /**
- * Return the remote listener associated with this
- * <code>EventRegistrationWatcher</code>. Optionally
- * prepare the listener if it has been recovered from
- * the store and not yet re-prepared.
- * @return the remote listener associated with this
- * <code>EventRegistrationWatcher</code>
- * @throws IOException if the listener can not
- * be unmarshalled. May throw {@link RemoteException}
- * if the call to the preparer does
- * @throws ClassNotFoundException if the listener
- * needs to be unmarshalled and a necessary
- * class can not be found
- * @throws SecurityException if the <code>prepareProxy</code>
- * call does.
- */
- abstract RemoteEventListener getListener(ProxyPreparer preparer)
- throws ClassNotFoundException, IOException;
-
- /**
- * Associate a <code>TemplateHandle</code> with this object. May
- * call more than once.
- *
- * @param h The <code>TemplateHandle</code> associate
- * with this watcher
- * @return <code>true</code> if the handle was successfully added,
- * and <code>false</code> if the watcher has already
- * been removed
- * @throws NullPointerException if <code>h</code> is
- * <code>null</code>
- */
- synchronized boolean addTemplateHandle(TemplateHandle h) {
- if (removed)
- return false; // Already removed!
-
- owners.add(h);
-
- if (server == null)
- server = h.getServer();
-
- return true;
- }
-
- /**
- * Set the expiration time of this object. This method may be
- * called before <code>setTemplateHandle</code> is called.
- * @param newExpiration The expiration time.
- */
- public final synchronized void setExpiration(long newExpiration) {
- expiration = newExpiration;
- }
-
- public final synchronized long getExpiration() {
- return expiration;
- }
-
- /**
- * Get the unique identifier associated with this object. This
- * method may be called before <code>setTemplateHandle</code> is
- * called.
- * @return The unique identifier associated with this
- * watcher.
- */
- public Uuid getCookie() {
- return cookie;
- }
-
- /**
- * Overridden by subclasses if there is any cleanup work they need
- * to do as part of <code>cancel</code> or
- * <code>removeIfExpired</code>. Called after releasing the lock
- * on <code>this</code>. Will be called at most once.
- * @param server A reference to the top level server object.
- * @param expired <code>true</code> if being called from
- * <code>removeIfExpired</code> and false otherwise.
- */
- void cleanup(OutriggerServerImpl server, boolean expired)
- {}
-
- /**
- * The heavy lifting of removing ourselves.
- * @param now The current time (or a bit earlier).
- * @param doIt If <code>true</code> ignore
- * <code>now</code> and just remove <code>this</code>
- * object.
- * @return <code>true</code> if this call removed
- * <code>this</code> object, <code>false</code> if
- * it had already been done. Should be ignored if
- * <code>doIt</code> is <code>false</code>.
- */
- private boolean doRemove(long now, boolean doIt) {
- final Set<TemplateHandle> owners;
- OutriggerServerImpl serv;
- synchronized (this) {
- if (removed) return false; // already removed
-
- // Is this a force, or past our expiration?
- if (!doIt && (now < expiration)) return false; // don't remove, not our time
-
- owners = new java.util.HashSet<TemplateHandle>(this.owners); // Don't need to clone
- this.owners.clear();
- removed = true;
- expiration = Long.MIN_VALUE; //Make sure no one tries to renew us
- serv = server;
- }
-
- cleanup(serv, !doIt);
- for (Iterator<TemplateHandle> i=owners.iterator(); i.hasNext(); ) {
- final TemplateHandle h = i.next();
- h.removeTransitionWatcher(this);
- }
-
- serv.removeEventRegistration(this);
- return true; // we did the deed
- }
-
- void removeIfExpired(long now) {
- doRemove(now, false);
- }
-
- public boolean cancel() {
- return doRemove(0, true);
- }
-
- /**
- * Common implementation of <code>EventSender</code> for visibility events
- */
- private class VisibilityEventSender implements EventSender {
- /** the <code>EntryRep</code> for the entry that became visible */
- final private EntryRep rep;
- /** the sequence number this event should have */
- final private long ourSeqNumber;
- /** <code>true</code> if this is a visibility event */
- final private boolean isVisible;
-
- /**
- * Create a new <code>VisibilityEventSender</code> that will send
- * a new <code>OutriggerAvailabilityEvent</code>.
- * @param rep the <code>EntryRep</code> for the entry
- * that became visible/available
- * @param isVisible <code>true</code> if this is a visibility event
- * @param ourSeqNumber the sequence number this event should have
- */
- private VisibilityEventSender(EntryRep rep, boolean isVisible,
- long ourSeqNumber)
- {
- this.rep = rep;
- this.ourSeqNumber = ourSeqNumber;
- this.isVisible = isVisible;
- }
-
- public void sendEvent(JavaSpace source, long now, ProxyPreparer preparer)
- throws UnknownEventException, IOException, ClassNotFoundException
- {
- boolean doneFor = false;
- RemoteEvent event;
- synchronized (AvailabilityRegistrationWatcher.this) {
- if (removed)
- return; // Our registration must been
- // canceled/expired, don't send event
-
- if (getExpiration() < now) {
- doneFor = true; // Our registration has expired, remove it
- }
-
-
- // Now that we are outside the lock kill our watcher if doneFor.
- if (doneFor) {
- cancel();
- return;
- }
- event = new OutriggerAvailabilityEvent(source, eventID, ourSeqNumber,
- handback, isVisible, rep);
- }// end sync(AvailabilityRegistrationWatcher.this)
- // Overridden keep out of sync block.
- getListener(preparer).notify( event );
- }
-
- public void cancelRegistration() {
- cancel();
- }
-
-// /**
-// * Since we try to send every event that occurs, don't
-// * care which order they run.
-// */
-// public boolean runAfter(EventSender other) {
-// return false;
-// }
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.river.outrigger;
+
+import java.io.IOException;
+import java.rmi.RemoteException;
+import java.rmi.MarshalledObject;
+import java.util.Set;
+import java.util.Iterator;
+import net.jini.core.event.RemoteEventListener;
+import net.jini.core.event.RemoteEvent;
+import net.jini.core.event.UnknownEventException;
+import net.jini.id.Uuid;
+import net.jini.security.ProxyPreparer;
+import net.jini.space.JavaSpace;
+import org.apache.river.outrigger.proxy.EntryRep;
+import org.apache.river.landlord.LeasedResource;
+import org.apache.river.outrigger.proxy.OutriggerAvailabilityEvent;
+
+
+/**
+ * Subclass of <code>TransitionWatcher</code> for availability event
+ * registrations. Also represents the event registration itself.
+ */
+abstract class AvailabilityRegistrationWatcher extends TransitionWatcher
+ implements EventRegistrationRecord
+{
+ /**
+ * The current expiration time of the registration
+ * Protected, but only for use by subclasses.
+ */
+ long expiration;
+
+ /**
+ * The UUID that identifies this registration
+ * Only for use by subclasses.
+ * Should not be changed.
+ */
+ volatile Uuid cookie;
+
+ /**
+ * The handback associated with this registration.
+ * Only for use by subclasses.
+ * Should not be changed.
+ */
+ MarshalledObject handback;
+
+ /**
+ * <code>true</code> if client is interested
+ * in only visibility events, <code>false</code>
+ * otherwise.
+ * Only for use by subclasses.
+ * Should not be changed.
+ */
+ volatile boolean visibilityOnly;
+
+ /**
+ * The event ID associated with this registration
+ * Protected, but only for use by subclasses.
+ * Should not be changed.
+ */
+ long eventID;
+
+ /**
+ * The current sequence number.
+ */
+ private long currentSeqNum = 0;
+
+ /**
+ * The <code>TemplateHandle</code>s associated with this
+ * watcher.
+ */
+ private final Set<TemplateHandle> owners = new java.util.HashSet<TemplateHandle>();
+ private boolean removed = false;
+
+ /**
+ * The OutriggerServerImpl we are part of.
+ */
+ private OutriggerServerImpl server;
+
+ /**
+ * Used during log recovery to create a mostly empty
+ * <code>AvailabilityRegistrationWatcher</code>.
+ * <p>
+ * Note, we set the time stamp and tie-breaker here instead of
+ * getting them from the log. This means they will be inconstant
+ * with their value from the last VM we were in, but since they
+ * never leak out and events are read-only anyway this should not
+ * be a problem (this also allows us to keep the tie-breaker and
+ * time stamp in final fields).
+ *
+ * @param timestamp the value that is used
+ * to sort <code>TransitionWatcher</code>s.
+ * @param startOrdinal the highest ordinal associated
+ * with operations that are considered to have occurred
+ * before the operation associated with this watcher.
+ * @param currentSeqNum Sequence number to start with.
+ */
+ AvailabilityRegistrationWatcher(long timestamp, long startOrdinal,
+ long currentSeqNum)
+ {
+ super(timestamp, startOrdinal);
+ this.currentSeqNum = currentSeqNum;
+ }
+
+ /**
+ * Create a new <code>AvailabilityRegistrationWatcher</code>.
+ * @param timestamp the value that is used
+ * to sort <code>TransitionWatcher</code>s.
+ * @param startOrdinal the highest ordinal associated
+ * with operations that are considered to have occurred
+ * before the operation associated with this watcher.
+ * @param cookie The unique identifier associated
+ * with this watcher. Must not be <code>null</code>.
+ * @param visibilityOnly pass <code>true</code> if client
+ * only wants visibility events
+ * @param handback The handback object that
+ * should be sent along with event
+ * notifications to the the listener.
+ * @param eventID The event ID for event type
+ * represented by this object.
+ * @throws NullPointerException if the <code>cookie</code>
+ * argument is <code>null</code>.
+ */
+ AvailabilityRegistrationWatcher(long timestamp, long startOrdinal,
+ Uuid cookie, boolean visibilityOnly, MarshalledObject handback,
+ long eventID)
+ {
+ super(timestamp, startOrdinal);
+
+ if (cookie == null)
+ throw new NullPointerException("cookie must be non-null");
+
+ this.cookie = cookie;
+ this.handback = handback;
+ this.eventID = eventID;
+ this.visibilityOnly = visibilityOnly;
+ }
+
+ /**
+ * Process the given transition by queuing up a task with the
+ * notifier for event delivery. Assumes the passed entry matches
+ * the template in the <code>TemplateHandle</code> associated with
+ * this watcher and that <code>isInterested</code> returned
+ * <code>true</code>. If <code>remove</code> has been called or
+ * the expiration time of this watcher has passed, this call
+ * should have no effect. This call may cause the watcher to be
+ * removed.
+ * @param transition A <code>EntryTransition</code> that
+ * describes the transition and what
+ * entry is transitioning. This method
+ * will assume that <code>transition.getHandle</code>
+ * returns a non-null value.
+ * @param now An estimate of the current time (not the time
+ * when the event occurred).
+ * @throws NullPointerException if <code>transition</code> is
+ * <code>null</code>.
+ */
+ void process(EntryTransition transition, long now) {
+ boolean doneFor = false;
+
+ // lock before checking the time and so we can update currentSeqNum
+ synchronized (this) {
+ if (removed) return; // Must have been removed
+
+ if (now > expiration) {
+ doneFor = true;
+ } else {
+ server.enqueueDelivery(
+ new VisibilityEventSender(
+ transition.getHandle().rep(),
+ transition.isVisible(),
+ currentSeqNum++));
+ }
+ }
+
+ if (doneFor) cancel();
+ }
+
+ /**
+ * Return the remote listener associated with this
+ * <code>EventRegistrationWatcher</code>. Optionally
+ * prepare the listener if it has been recovered from
+ * the store and not yet re-prepared.
+ * @return the remote listener associated with this
+ * <code>EventRegistrationWatcher</code>
+ * @throws IOException if the listener can not
+ * be unmarshalled. May throw {@link RemoteException}
+ * if the call to the preparer does
+ * @throws ClassNotFoundException if the listener
+ * needs to be unmarshalled and a necessary
+ * class can not be found
+ * @throws SecurityException if the <code>prepareProxy</code>
+ * call does.
+ */
+ abstract RemoteEventListener getListener(ProxyPreparer preparer)
+ throws ClassNotFoundException, IOException;
+
+ /**
+ * Associate a <code>TemplateHandle</code> with this object. May
+ * call more than once.
+ *
+ * @param h The <code>TemplateHandle</code> associate
+ * with this watcher
+ * @return <code>true</code> if the handle was successfully added,
+ * and <code>false</code> if the watcher has already
+ * been removed
+ * @throws NullPointerException if <code>h</code> is
+ * <code>null</code>
+ */
+ synchronized boolean addTemplateHandle(TemplateHandle h) {
+ if (removed)
+ return false; // Already removed!
+
+ owners.add(h);
+
+ if (server == null)
+ server = h.getServer();
+
+ return true;
+ }
+
+ /**
+ * Set the expiration time of this object. This method may be
+ * called before <code>setTemplateHandle</code> is called.
+ * @param newExpiration The expiration time.
+ */
+ public final synchronized void setExpiration(long newExpiration) {
+ expiration = newExpiration;
+ }
+
+ public final synchronized long getExpiration() {
+ return expiration;
+ }
+
+ /**
+ * Get the unique identifier associated with this object. This
+ * method may be called before <code>setTemplateHandle</code> is
+ * called.
+ * @return The unique identifier associated with this
+ * watcher.
+ */
+ public Uuid getCookie() {
+ return cookie;
+ }
+
+ /**
+ * Overridden by subclasses if there is any cleanup work they need
+ * to do as part of <code>cancel</code> or
+ * <code>removeIfExpired</code>. Called after releasing the lock
+ * on <code>this</code>. Will be called at most once.
+ * @param server A reference to the top level server object.
+ * @param expired <code>true</code> if being called from
+ * <code>removeIfExpired</code> and false otherwise.
+ */
+ void cleanup(OutriggerServerImpl server, boolean expired)
+ {}
+
+ /**
+ * The heavy lifting of removing ourselves.
+ * @param now The current time (or a bit earlier).
+ * @param doIt If <code>true</code> ignore
+ * <code>now</code> and just remove <code>this</code>
+ * object.
+ * @return <code>true</code> if this call removed
+ * <code>this</code> object, <code>false</code> if
+ * it had already been done. Should be ignored if
+ * <code>doIt</code> is <code>false</code>.
+ */
+ private boolean doRemove(long now, boolean doIt) {
+ final Set<TemplateHandle> owners;
+ OutriggerServerImpl serv;
+ synchronized (this) {
+ if (removed) return false; // already removed
+
+ // Is this a force, or past our expiration?
+ if (!doIt && (now < expiration)) return false; // don't remove, not our time
+
+ owners = new java.util.HashSet<TemplateHandle>(this.owners); // Don't need to clone
+ this.owners.clear();
+ removed = true;
+ expiration = Long.MIN_VALUE; //Make sure no one tries to renew us
+ serv = server;
+ }
+
+ cleanup(serv, !doIt);
+ for (Iterator<TemplateHandle> i=owners.iterator(); i.hasNext(); ) {
+ final TemplateHandle h = i.next();
+ h.removeTransitionWatcher(this);
+ }
+
+ serv.removeEventRegistration(this);
+ return true; // we did the deed
+ }
+
+ void removeIfExpired(long now) {
+ doRemove(now, false);
+ }
+
+ public boolean cancel() {
+ return doRemove(0, true);
+ }
+
+ /**
+ * Common implementation of <code>EventSender</code> for visibility events
+ */
+ private class VisibilityEventSender implements EventSender {
+ /** the <code>EntryRep</code> for the entry that became visible */
+ final private EntryRep rep;
+ /** the sequence number this event should have */
+ final private long ourSeqNumber;
+ /** <code>true</code> if this is a visibility event */
+ final private boolean isVisible;
+
+ /**
+ * Create a new <code>VisibilityEventSender</code> that will send
+ * a new <code>OutriggerAvailabilityEvent</code>.
+ * @param rep the <code>EntryRep</code> for the entry
+ * that became visible/available
+ * @param isVisible <code>true</code> if this is a visibility event
+ * @param ourSeqNumber the sequence number this event should have
+ */
+ private VisibilityEventSender(EntryRep rep, boolean isVisible,
+ long ourSeqNumber)
+ {
+ this.rep = rep;
+ this.ourSeqNumber = ourSeqNumber;
+ this.isVisible = isVisible;
+ }
+
+ public void sendEvent(JavaSpace source, long now, ProxyPreparer preparer)
+ throws UnknownEventException, IOException, ClassNotFoundException
+ {
+ boolean doneFor = false;
+ RemoteEvent event;
+ synchronized (AvailabilityRegistrationWatcher.this) {
+ if (removed)
+ return; // Our registration must been
+ // canceled/expired, don't send event
+
+ if (getExpiration() < now) {
+ doneFor = true; // Our registration has expired, remove it
+ }
+
+
+ // Now that we are outside the lock kill our watcher if doneFor.
+ if (doneFor) {
+ cancel();
+ return;
+ }
+ event = new OutriggerAvailabilityEvent(source, eventID, ourSeqNumber,
+ handback, isVisible, rep);
+ }// end sync(AvailabilityRegistrationWatcher.this)
+ // Overridden keep out of sync block.
+ getListener(preparer).notify( event );
+ }
+
+ public void cancelRegistration() {
+ cancel();
+ }
+
+// /**
+// * Since we try to send every event that occurs, don't
+// * care which order they run.
+// */
+// public boolean runAfter(EventSender other) {
+// return false;
+// }
+ }
+}
Modified: river/jtsk/modules/modularize/apache-river/river-services/outrigger/outrigger-service/src/main/java/org/apache/river/outrigger/BaseHandle.java
URL: http://svn.apache.org/viewvc/river/jtsk/modules/modularize/apache-river/river-services/outrigger/outrigger-service/src/main/java/org/apache/river/outrigger/BaseHandle.java?rev=1879521&r1=1879520&r2=1879521&view=diff
==============================================================================
--- river/jtsk/modules/modularize/apache-river/river-services/outrigger/outrigger-service/src/main/java/org/apache/river/outrigger/BaseHandle.java (original)
+++ river/jtsk/modules/modularize/apache-river/river-services/outrigger/outrigger-service/src/main/java/org/apache/river/outrigger/BaseHandle.java Sun Jul 5 11:41:39 2020
@@ -1,70 +1,71 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.
- */
-package org.apache.river.outrigger;
-
-import java.util.Queue;
-
-/**
- * Base class for handles to Entries and templates.
- *
- * @author Sun Microsystems, Inc.
- *
- */
-abstract class BaseHandle {
- private final EntryRep rep; // the rep this handle manages
- private final Queue<? extends BaseHandle> content;
-
- /**
- * Create a new handle
- *
- * @param content thread safe Queue from which this BaseHandle will be removed
- * atomically, BaseHandle is not added to content during construction,
- * as it would allow this to escape.
- * @param rep EntryRep managed by this BaseHandle.
- */
- protected BaseHandle(EntryRep rep, Queue<? extends BaseHandle> content) {
- this.rep = rep;
- this.content = content;
- }
-
- /**
- * Return the handle's <code>EntryRep</code> object.
- */
- EntryRep rep() {
- return rep;
- }
-
- // inherit doc comment
- public String classFor() {
- return rep.classFor();
- }
-
- public abstract boolean removed();
-
- /**
- * Overridden and called from subclass.
- *
- * @return true if removed.
- */
- public boolean remove(){
- return content.remove(this);
- }
-}
-
-
-
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.river.outrigger;
+
+import java.util.Queue;
+import org.apache.river.outrigger.proxy.EntryRep;
+
+/**
+ * Base class for handles to Entries and templates.
+ *
+ * @author Sun Microsystems, Inc.
+ *
+ */
+abstract class BaseHandle {
+ private final EntryRep rep; // the rep this handle manages
+ private final Queue<? extends BaseHandle> content;
+
+ /**
+ * Create a new handle
+ *
+ * @param content thread safe Queue from which this BaseHandle will be removed
+ * atomically, BaseHandle is not added to content during construction,
+ * as it would allow this to escape.
+ * @param rep EntryRep managed by this BaseHandle.
+ */
+ protected BaseHandle(EntryRep rep, Queue<? extends BaseHandle> content) {
+ this.rep = rep;
+ this.content = content;
+ }
+
+ /**
+ * Return the handle's <code>EntryRep</code> object.
+ */
+ EntryRep rep() {
+ return rep;
+ }
+
+ // inherit doc comment
+ public String classFor() {
+ return rep.classFor();
+ }
+
+ public abstract boolean removed();
+
+ /**
+ * Overridden and called from subclass.
+ *
+ * @return true if removed.
+ */
+ public boolean remove(){
+ return content.remove(this);
+ }
+}
+
+
+
Modified: river/jtsk/modules/modularize/apache-river/river-services/outrigger/outrigger-service/src/main/java/org/apache/river/outrigger/EntryHandle.java
URL: http://svn.apache.org/viewvc/river/jtsk/modules/modularize/apache-river/river-services/outrigger/outrigger-service/src/main/java/org/apache/river/outrigger/EntryHandle.java?rev=1879521&r1=1879520&r2=1879521&view=diff
==============================================================================
--- river/jtsk/modules/modularize/apache-river/river-services/outrigger/outrigger-service/src/main/java/org/apache/river/outrigger/EntryHandle.java (original)
+++ river/jtsk/modules/modularize/apache-river/river-services/outrigger/outrigger-service/src/main/java/org/apache/river/outrigger/EntryHandle.java Sun Jul 5 11:41:39 2020
@@ -1,456 +1,458 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.
- */
-package org.apache.river.outrigger;
-
-import net.jini.io.MarshalledInstance;
-import org.apache.river.landlord.LeasedResource;
-import java.util.Queue;
-
-/**
- * This object holds an annotated reference to an
- * <code>EntryRep</code> object. Currently there is one annotation,
- * which is a hash code for the object that can be used as a
- * quick-reject comparison when scanning through the list. The handle
- * holds a hash code that is based on the bytes that encode the first
- * <i>N</i> fields, where <i>N</i> is the number of fields in the
- * entry up to a maximum (currently this maximum is 16 (64 bits
- * divided by 4 bits/field), so that 4 is the minimum number of bits
- * per field in the hash).
- * <p>
- * When comparing, the template's own hash is calculated, and also a
- * mask that masks out the hash codes of wildcard fields. A template
- * will match an entry only if the entry's EntryHandle hash masked with
- * the template's wildcard mask is the same as the template's hash.
- * <p>
- * Care must be taken since the template may be a supertype of the type
- * being searched. This is why the number of fields in the static
- * methods is passed as an argument, not simply taken from the entry in
- * question. When a template's hash is being created, its hash value
- * is calculated as if it were of the class being searched, with the
- * subclass's field count. Any extra fields are assumed to be
- * wildcards. This means that the template's hash must be recalculated
- * for each subclass it is compared against, but this only happens once
- * per known subclass, and so is probably not onerous. <p>
- *
- * There is a particular risk with the removal of entries outside of
- * transactions. Ideally marking an entry as removed and making the
- * removal durable would be atomic with respect to other
- * operations. But this would require holding a lock across disk I/O
- * which we try to avoid. In particular it would hold up the progress
- * of searches that match the entry in question, even though the very
- * next entry might be a suitable match. One alternative would be to
- * make the removal durable, then while holding the entry's lock mark
- * the entry as removed, but this would allow competing takes to both
- * get the same entry (this could be corrected by making the 2nd take
- * lose when it goes back to try and complete the removal, and then
- * continues its query, but since logging happens up in
- * OutriggerServerImpl restarting the query would be inconvenient, it
- * would probably also result in a number of unnecessary log
- * records). We could mark the entry as removed, release the entry's
- * lock, and then make the removal durable. However, this allows for
- * the possibility of a 2nd query that matches the entry coming in
- * after the entry has been removed, but before the removal has been
- * made durable, finding no matches and returning null, and then the
- * server crashing before the removal is made durable. When the server
- * came back up the entry would be available again, and if the 2nd
- * query was repeated it could then return the entry that had been
- * marked as removed. Effectively an entry would have disappeared and
- * then reappeared. <p>
- *
- * Our solution is to introduce the <i>removePending</i> flag. When an
- * entry is to be removed outside of a transaction the removePending
- * flag is set by calling <code>provisionallyRemove</code>, the
- * removal is made durable, the entry is removed internally and the
- * removePending flag cleared (generally by calling
- * <code>remove</code> on the appropriate <code>EntryHolder</code> or
- * on the <code>EntryHolderSet</code> - either will remove the entry
- * from all the internal tables and clear the removePending flag). <p>
- *
- * Any operation that will definitively indicate that a given entry
- * has been removed must not only check to see if the entry has been
- * removed but also that removePending is not set (the
- * <code>isProvisionallyRemoved</code> method returns the state of the
- * removePending flag). If removePending is set the operation must
- * either block until removePending is cleared (this can be
- * accomplished using the <code>waitOnCompleteRemoval</code> method),
- * indicating that the removal has been made durable, or return in
- * such a way that the entry's state is left ambiguous. Note, because
- * any I/O failure while logging will result in the space crashing a
- * set removePending flag will only transition to cleared after a
- * removal has been made durable, thus an operation blocked on the
- * removePending flag should never need to go back and see if the
- * entry has become available. <p>
- *
- * Note some of the method of this class are synchronized internally,
- * while other are synchronized externally. Methods which need to be
- * synchronized externally are called out in their comments.
- *
- * @author Sun Microsystems, Inc.
- */
-// We do not store this data on the EntryRep object itself because it
-// is not really part of the client<->JavaSpaces service protocol --
-// some implementations of EntryHolder may not choose to use this
-// mechanism. It does add an extra object per EntryRep object in
-// those that *do* use it, and so we may want to re-examine this in the
-// future.
-
-class EntryHandle extends BaseHandle implements LeaseDesc, Transactable {
- /** the content hash for the rep */
- private final long hash; // Made final for toString() and hash().
-
- /**
- * If this entry is locked by one or more transaction the info
- * on those transactions, otherwise <code>null</code>.
- */
- private TxnState txnState;
-
- /**
- * <code>true</code> if this entry has to been seen as removed,
- * but the removal has not yet been committed to disk
- */
- private boolean removePending = false;
- private boolean removed = false;
-
- /**
- * Create a new handle, calculating the hash for the object.
- * If <code>mgr</code> is non-<code>null</code> start the entry
- * as write locked under the given transaction.
- * @param rep The rep of the entry this is a handle for
- * @param mgr If this entry is being written under a transaction the
- * manager for that transaction, otherwise <code>null</code>
- * @param holder If mgr is non-<code>null</code> this must be
- * the holder holding this handle. Otherwise it may be
- * <code>null</code>
- * @param content Queue this EntryHandle will be removed from.
- */
- EntryHandle(EntryRep rep, TransactableMgr mgr, EntryHolder holder, Queue<EntryHandle> content) {
- super(rep, content);
- hash = (rep != null ? hashFor(rep, rep.numFields())[0] : -1);
- if (mgr == null) {
- txnState = null;
- } else {
- if (holder == null)
- throw new NullPointerException("EntryHandle:If mgr is " +
- "non-null holder must be non-null");
- txnState = new TxnState(mgr, TransactableMgr.WRITE, holder);
- }
- }
-
- // inherit doc comment
- public LeasedResource getLeasedResource() {
- return rep();
- }
-
- /**
- * Return this handle's content hash.
- */
- long hash() {
- return hash;
- }
-
- /**
- * Calculate the hash for a particular entry, assuming the given
- * number of fields, filling in the fields of <code>desc</code>
- * with the relevant values. <code>desc</code> may be
- * <code>null</code>. <code>numFields</code> must be >= the number
- * of fields in the <code>rep</code> object (this is not
- * checked).
- *
- * @see #hashFor(EntryRep,int)
- * @see #descFor(EntryRep,int)
- * @return long[4] containing the hash, bitsPerField, fieldsInHash and mask
- * in that order.
- */
- private static long []
- hashFor(EntryRep rep, int numFields)
- {
- long [] result = new long [4];
- if (rep == null || numFields == 0) return result;
-
- /** Number of bits allocated in the hash for each field */
- int bitsPerField = Math.max(64 / numFields, 4); // at least 4 bits
- /** How many fields are used in the hash? */
- int fieldsInHash = 64 / bitsPerField; // max fields used
- /** A mask with the lower <code>bitsPerField</code> bits set */
- long mask = // per-field bit mask
- 0xffffffffffffffffL >>> (64 - bitsPerField);
- long hash = 0; // current hash value
-
- // field counts will be different if rep is a template of a superclass
- long endField = Math.min(fieldsInHash, rep.numFields());
-
- // set the appropriate rep of the overall hash for the field's hash
- for (int i = 0; i < endField; i++)
- hash |= (hashForField(rep, i) & mask) << (i * bitsPerField);
-
- result [0] = hash;
- result [1] = bitsPerField;
- result [2] = fieldsInHash;
- result [3] = mask;
- return result;
- }
-
- /**
- * Return the template description -- mask and hash.
- *
- * @see EntryHandleTmplDesc
- */
- static EntryHandleTmplDesc descFor(EntryRep tmpl, int numFields) {
- EntryHandleTmplDesc tmplDesc;
-
- // Get the hash and the related useful information
- long [] hashDesc = hashFor(tmpl, numFields);
- long hash = hashDesc[0];
- long bitsPerField = hashDesc [1];
- long fieldsInHash = hashDesc [2];
- long mask = hashDesc [3];
-
- long tmplMask = 0;
-
- // Create the mask to mask away wildcard fields
- for (int i = 0; i < fieldsInHash; i++) {
- // If this field is one we have a value for, set bits in the mask
- if (i < tmpl.numFields() && tmpl.value(i) != null)
- tmplMask |= (mask << (i * bitsPerField));
- }
-
- // Ensure that the non-value fields are masked out
- hash &= tmplMask;
-
- tmplDesc = new EntryHandleTmplDesc(hash, tmplMask);
-
- return tmplDesc;
- }
-
- /**
- * Return the hash value for a given field, which is then merged in
- * as part of the overall hash for the entry. The last 32 bytes of
- * the field value are used (or fewer if there are fewer).
- *
- * @see #hashFor(EntryRep,int)
- */
- static long hashForField(EntryRep rep, int field) {
- MarshalledInstance v = rep.value(field);
- if (v == null) // for templates, it's just zero
- return 0;
- else
- return v.hashCode();
- }
-
- public String toString() {
- return "0x" + Long.toHexString(hash) + " [" + rep() + "]";
- }
-
- /**
- * Return <code>true</code> if the operation <code>op</code> under
- * the given transaction (represented by the transaction's manager)
- * can be performed on the object represented by this handle. The
- * thread calling this method should own this object's lock.
- */
- // $$$ Calling this method when we don't own the lock on this
- // object seems a bit dicey, but that is exactly what we do in
- // EntryHolder.SimpleRepEnum.nextRep(). Working it through
- // it seems to work in that particular case, but it seems fragile.
- boolean canPerform(TransactableMgr mgr, int op) {
- synchronized (this){ // Audit revealed calling thread didn't always own lock see comment above.
- if (txnState == null)
- return true; // all operations are legal on a non-transacted entry
-
- return txnState.canPerform(mgr, op);
- }
- }
-
- /**
- * Return <code>true</code> if the given transaction is already
- * known to the entry this handle represents. The
- * thread calling this method should own this object's lock.
- */
- boolean knownMgr(TransactableMgr mgr) {
- synchronized (this){ // Audit revealed caller methods didn't always hold lock.
- if (txnState == null)
- return (mgr == null); // The only mgr we know about is the null mgr
-
- return txnState.knownMgr(mgr);
- }
- }
-
- /**
- * Return <code>true</code> if we are being managed the given
- * manager is the only one we know about. The thread calling this
- * method should own this object's lock.
- */
- boolean onlyMgr(TransactableMgr mgr) {
- if (txnState == null) // Audit revealed caller always held lock.
- return false;
-
- return txnState.onlyMgr(mgr);
- }
-
- /**
- * Return <code>true</code> if the entry this handle represents is
- * being managed within any transaction. The thread calling this
- * method should own this object's lock.
- */
- boolean managed() {
- synchronized (this){ // Audit revealed caller didn't always have lock.
- return txnState != null;
- }
- }
-
- /**
- * Add into the collection any transactions that are known to this
- * handle. The thread calling this method should own this object's
- * lock.
- */
- void addTxns(java.util.Collection collection) {
- if (txnState == null) // Confirmed that calling method owns lock.
- return; // nothing to add
-
- txnState.addTxns(collection);
- }
-
- /**
- * Add <code>mgr</code> to the list of known managers, setting the
- * the type of lock on this entry to <code>op</code>. The thread
- * calling this method should own this object's lock. Assumes
- * that <code>op</code> is compatible with any lock currently
- * associated with this entry. <code>holder</code> is the the
- * <code>EntryHolder</code> holding this handle.
- */
- void add(TransactableMgr mgr, int op, EntryHolder holder) {
- synchronized (this){
- if (txnState == null) {
- txnState = new TxnState(mgr, op, holder);
- } else {
- txnState.add(mgr, op);
- }
- }
- }
-
- /**
- * It this entry is read locked promote to take locked and return
- * true, otherwise return false. Assumes that the object is
- * locked and the take is being performed under the one
- * transaction that owns a lock on the entry.
- */
- boolean promoteToTakeIfNeeded() {
- synchronized (this){
- return txnState.promoteToTakeIfNeeded();
- }
- }
-
- /**
- * Returns <code>true</code> it this entry has been removed
- * outside of a transaction, but that removal has not yet been
- * committed to disk.The thread calling this method should own this
- * object's lock.
- */
- boolean isProvisionallyRemoved() {
- assert Thread.holdsLock(this);
- return removePending;
- }
-
- /**
- * Marks this entry as being removed outside of a transaction but
- * not yet committed to disk. The thread calling this method should
- * own this object's lock.
- */
- void provisionallyRemove() {
- assert Thread.holdsLock(this);
- assert !removePending;
- removePending = true;
- }
-
- /**
- * Called after the removal of a provisionally removed entry has
- * been committed to disk and the handle has been removed from its
- * holder. The thread calling this method should own this object's
- * lock.
- */
- void removalComplete() {
- assert Thread.holdsLock(this);
-
- if (removePending) {
- removePending = false;
- notifyAll();
- }
- }
-
- /**
- * If this entry has been marked for removal by a
- * non-transactional operation, but that operation has not be
- * yet been committed to disk, block until the operation has been
- * committed to disk, otherwise return immediately. The
- * thread calling this method should own this object's lock.
- */
- void waitOnCompleteRemoval() throws InterruptedException {
- assert Thread.holdsLock(this);
- while (removePending) {
- wait();
- }
- }
-
- /**************************************************
- * Methods required by the Transactable interface
- **************************************************/
- public synchronized int prepare(TransactableMgr mgr,
- OutriggerServerImpl space)
- {
- if (txnState == null)
- throw new IllegalStateException("Can't prepare an entry not " +
- "involved in a transaction");
- final int rslt = txnState.prepare(mgr, space, this);
- if (txnState.empty())
- txnState = null;
-
- return rslt;
- }
-
- public synchronized void abort(TransactableMgr mgr,
- OutriggerServerImpl space)
- {
- if (txnState == null)
- throw new IllegalStateException("Can't abort an entry not " +
- "involved in a transaction");
- final boolean last = txnState.abort(mgr, space, this);
- if (last)
- txnState = null;
- }
-
- public synchronized void commit(TransactableMgr mgr,
- OutriggerServerImpl space)
- {
- if (txnState == null)
- throw new IllegalStateException("Can't commit an entry not " +
- "involved in a transaction");
-
- final boolean last = txnState.commit(mgr, space, this);
- if (last)
- txnState = null;
- }
-
- @Override
- public synchronized boolean removed() {
- return removed;
- }
-
- public synchronized boolean remove() {
- if (!removed) removed = super.remove();
- return removed;
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.river.outrigger;
+
+import net.jini.io.MarshalledInstance;
+import org.apache.river.landlord.LeasedResource;
+import java.util.Queue;
+import org.apache.river.outrigger.proxy.EntryRep;
+
+
+/**
+ * This object holds an annotated reference to an
+ * <code>EntryRep</code> object. Currently there is one annotation,
+ * which is a hash code for the object that can be used as a
+ * quick-reject comparison when scanning through the list. The handle
+ * holds a hash code that is based on the bytes that encode the first
+ * <i>N</i> fields, where <i>N</i> is the number of fields in the
+ * entry up to a maximum (currently this maximum is 16 (64 bits
+ * divided by 4 bits/field), so that 4 is the minimum number of bits
+ * per field in the hash).
+ * <p>
+ * When comparing, the template's own hash is calculated, and also a
+ * mask that masks out the hash codes of wildcard fields. A template
+ * will match an entry only if the entry's EntryHandle hash masked with
+ * the template's wildcard mask is the same as the template's hash.
+ * <p>
+ * Care must be taken since the template may be a supertype of the type
+ * being searched. This is why the number of fields in the static
+ * methods is passed as an argument, not simply taken from the entry in
+ * question. When a template's hash is being created, its hash value
+ * is calculated as if it were of the class being searched, with the
+ * subclass's field count. Any extra fields are assumed to be
+ * wildcards. This means that the template's hash must be recalculated
+ * for each subclass it is compared against, but this only happens once
+ * per known subclass, and so is probably not onerous. <p>
+ *
+ * There is a particular risk with the removal of entries outside of
+ * transactions. Ideally marking an entry as removed and making the
+ * removal durable would be atomic with respect to other
+ * operations. But this would require holding a lock across disk I/O
+ * which we try to avoid. In particular it would hold up the progress
+ * of searches that match the entry in question, even though the very
+ * next entry might be a suitable match. One alternative would be to
+ * make the removal durable, then while holding the entry's lock mark
+ * the entry as removed, but this would allow competing takes to both
+ * get the same entry (this could be corrected by making the 2nd take
+ * lose when it goes back to try and complete the removal, and then
+ * continues its query, but since logging happens up in
+ * OutriggerServerImpl restarting the query would be inconvenient, it
+ * would probably also result in a number of unnecessary log
+ * records). We could mark the entry as removed, release the entry's
+ * lock, and then make the removal durable. However, this allows for
+ * the possibility of a 2nd query that matches the entry coming in
+ * after the entry has been removed, but before the removal has been
+ * made durable, finding no matches and returning null, and then the
+ * server crashing before the removal is made durable. When the server
+ * came back up the entry would be available again, and if the 2nd
+ * query was repeated it could then return the entry that had been
+ * marked as removed. Effectively an entry would have disappeared and
+ * then reappeared. <p>
+ *
+ * Our solution is to introduce the <i>removePending</i> flag. When an
+ * entry is to be removed outside of a transaction the removePending
+ * flag is set by calling <code>provisionallyRemove</code>, the
+ * removal is made durable, the entry is removed internally and the
+ * removePending flag cleared (generally by calling
+ * <code>remove</code> on the appropriate <code>EntryHolder</code> or
+ * on the <code>EntryHolderSet</code> - either will remove the entry
+ * from all the internal tables and clear the removePending flag). <p>
+ *
+ * Any operation that will definitively indicate that a given entry
+ * has been removed must not only check to see if the entry has been
+ * removed but also that removePending is not set (the
+ * <code>isProvisionallyRemoved</code> method returns the state of the
+ * removePending flag). If removePending is set the operation must
+ * either block until removePending is cleared (this can be
+ * accomplished using the <code>waitOnCompleteRemoval</code> method),
+ * indicating that the removal has been made durable, or return in
+ * such a way that the entry's state is left ambiguous. Note, because
+ * any I/O failure while logging will result in the space crashing a
+ * set removePending flag will only transition to cleared after a
+ * removal has been made durable, thus an operation blocked on the
+ * removePending flag should never need to go back and see if the
+ * entry has become available. <p>
+ *
+ * Note some of the method of this class are synchronized internally,
+ * while other are synchronized externally. Methods which need to be
+ * synchronized externally are called out in their comments.
+ *
+ * @author Sun Microsystems, Inc.
+ */
+// We do not store this data on the EntryRep object itself because it
+// is not really part of the client<->JavaSpaces service protocol --
+// some implementations of EntryHolder may not choose to use this
+// mechanism. It does add an extra object per EntryRep object in
+// those that *do* use it, and so we may want to re-examine this in the
+// future.
+
+class EntryHandle extends BaseHandle implements LeaseDesc, Transactable {
+ /** the content hash for the rep */
+ private final long hash; // Made final for toString() and hash().
+
+ /**
+ * If this entry is locked by one or more transaction the info
+ * on those transactions, otherwise <code>null</code>.
+ */
+ private TxnState txnState;
+
+ /**
+ * <code>true</code> if this entry has to been seen as removed,
+ * but the removal has not yet been committed to disk
+ */
+ private boolean removePending = false;
+ private boolean removed = false;
+
+ /**
+ * Create a new handle, calculating the hash for the object.
+ * If <code>mgr</code> is non-<code>null</code> start the entry
+ * as write locked under the given transaction.
+ * @param rep The rep of the entry this is a handle for
+ * @param mgr If this entry is being written under a transaction the
+ * manager for that transaction, otherwise <code>null</code>
+ * @param holder If mgr is non-<code>null</code> this must be
+ * the holder holding this handle. Otherwise it may be
+ * <code>null</code>
+ * @param content Queue this EntryHandle will be removed from.
+ */
+ EntryHandle(EntryRep rep, TransactableMgr mgr, EntryHolder holder, Queue<EntryHandle> content) {
+ super(rep, content);
+ hash = (rep != null ? hashFor(rep, rep.numFields())[0] : -1);
+ if (mgr == null) {
+ txnState = null;
+ } else {
+ if (holder == null)
+ throw new NullPointerException("EntryHandle:If mgr is " +
+ "non-null holder must be non-null");
+ txnState = new TxnState(mgr, TransactableMgr.WRITE, holder);
+ }
+ }
+
+ // inherit doc comment
+ public LeasedResource getLeasedResource() {
+ return rep();
+ }
+
+ /**
+ * Return this handle's content hash.
+ */
+ long hash() {
+ return hash;
+ }
+
+ /**
+ * Calculate the hash for a particular entry, assuming the given
+ * number of fields, filling in the fields of <code>desc</code>
+ * with the relevant values. <code>desc</code> may be
+ * <code>null</code>. <code>numFields</code> must be >= the number
+ * of fields in the <code>rep</code> object (this is not
+ * checked).
+ *
+ * @see #hashFor(EntryRep,int)
+ * @see #descFor(EntryRep,int)
+ * @return long[4] containing the hash, bitsPerField, fieldsInHash and mask
+ * in that order.
+ */
+ private static long []
+ hashFor(EntryRep rep, int numFields)
+ {
+ long [] result = new long [4];
+ if (rep == null || numFields == 0) return result;
+
+ /** Number of bits allocated in the hash for each field */
+ int bitsPerField = Math.max(64 / numFields, 4); // at least 4 bits
+ /** How many fields are used in the hash? */
+ int fieldsInHash = 64 / bitsPerField; // max fields used
+ /** A mask with the lower <code>bitsPerField</code> bits set */
+ long mask = // per-field bit mask
+ 0xffffffffffffffffL >>> (64 - bitsPerField);
+ long hash = 0; // current hash value
+
+ // field counts will be different if rep is a template of a superclass
+ long endField = Math.min(fieldsInHash, rep.numFields());
+
+ // set the appropriate rep of the overall hash for the field's hash
+ for (int i = 0; i < endField; i++)
+ hash |= (hashForField(rep, i) & mask) << (i * bitsPerField);
+
+ result [0] = hash;
+ result [1] = bitsPerField;
+ result [2] = fieldsInHash;
+ result [3] = mask;
+ return result;
+ }
+
+ /**
+ * Return the template description -- mask and hash.
+ *
+ * @see EntryHandleTmplDesc
+ */
+ static EntryHandleTmplDesc descFor(EntryRep tmpl, int numFields) {
+ EntryHandleTmplDesc tmplDesc;
+
+ // Get the hash and the related useful information
+ long [] hashDesc = hashFor(tmpl, numFields);
+ long hash = hashDesc[0];
+ long bitsPerField = hashDesc [1];
+ long fieldsInHash = hashDesc [2];
+ long mask = hashDesc [3];
+
+ long tmplMask = 0;
+
+ // Create the mask to mask away wildcard fields
+ for (int i = 0; i < fieldsInHash; i++) {
+ // If this field is one we have a value for, set bits in the mask
+ if (i < tmpl.numFields() && tmpl.value(i) != null)
+ tmplMask |= (mask << (i * bitsPerField));
+ }
+
+ // Ensure that the non-value fields are masked out
+ hash &= tmplMask;
+
+ tmplDesc = new EntryHandleTmplDesc(hash, tmplMask);
+
+ return tmplDesc;
+ }
+
+ /**
+ * Return the hash value for a given field, which is then merged in
+ * as part of the overall hash for the entry. The last 32 bytes of
+ * the field value are used (or fewer if there are fewer).
+ *
+ * @see #hashFor(EntryRep,int)
+ */
+ static long hashForField(EntryRep rep, int field) {
+ MarshalledInstance v = rep.value(field);
+ if (v == null) // for templates, it's just zero
+ return 0;
+ else
+ return v.hashCode();
+ }
+
+ public String toString() {
+ return "0x" + Long.toHexString(hash) + " [" + rep() + "]";
+ }
+
+ /**
+ * Return <code>true</code> if the operation <code>op</code> under
+ * the given transaction (represented by the transaction's manager)
+ * can be performed on the object represented by this handle. The
+ * thread calling this method should own this object's lock.
+ */
+ // $$$ Calling this method when we don't own the lock on this
+ // object seems a bit dicey, but that is exactly what we do in
+ // EntryHolder.SimpleRepEnum.nextRep(). Working it through
+ // it seems to work in that particular case, but it seems fragile.
+ boolean canPerform(TransactableMgr mgr, int op) {
+ synchronized (this){ // Audit revealed calling thread didn't always own lock see comment above.
+ if (txnState == null)
+ return true; // all operations are legal on a non-transacted entry
+
+ return txnState.canPerform(mgr, op);
+ }
+ }
+
+ /**
+ * Return <code>true</code> if the given transaction is already
+ * known to the entry this handle represents. The
+ * thread calling this method should own this object's lock.
+ */
+ boolean knownMgr(TransactableMgr mgr) {
+ synchronized (this){ // Audit revealed caller methods didn't always hold lock.
+ if (txnState == null)
+ return (mgr == null); // The only mgr we know about is the null mgr
+
+ return txnState.knownMgr(mgr);
+ }
+ }
+
+ /**
+ * Return <code>true</code> if we are being managed the given
+ * manager is the only one we know about. The thread calling this
+ * method should own this object's lock.
+ */
+ boolean onlyMgr(TransactableMgr mgr) {
+ if (txnState == null) // Audit revealed caller always held lock.
+ return false;
+
+ return txnState.onlyMgr(mgr);
+ }
+
+ /**
+ * Return <code>true</code> if the entry this handle represents is
+ * being managed within any transaction. The thread calling this
+ * method should own this object's lock.
+ */
+ boolean managed() {
+ synchronized (this){ // Audit revealed caller didn't always have lock.
+ return txnState != null;
+ }
+ }
+
+ /**
+ * Add into the collection any transactions that are known to this
+ * handle. The thread calling this method should own this object's
+ * lock.
+ */
+ void addTxns(java.util.Collection collection) {
+ if (txnState == null) // Confirmed that calling method owns lock.
+ return; // nothing to add
+
+ txnState.addTxns(collection);
+ }
+
+ /**
+ * Add <code>mgr</code> to the list of known managers, setting the
+ * the type of lock on this entry to <code>op</code>. The thread
+ * calling this method should own this object's lock. Assumes
+ * that <code>op</code> is compatible with any lock currently
+ * associated with this entry. <code>holder</code> is the the
+ * <code>EntryHolder</code> holding this handle.
+ */
+ void add(TransactableMgr mgr, int op, EntryHolder holder) {
+ synchronized (this){
+ if (txnState == null) {
+ txnState = new TxnState(mgr, op, holder);
+ } else {
+ txnState.add(mgr, op);
+ }
+ }
+ }
+
+ /**
+ * It this entry is read locked promote to take locked and return
+ * true, otherwise return false. Assumes that the object is
+ * locked and the take is being performed under the one
+ * transaction that owns a lock on the entry.
+ */
+ boolean promoteToTakeIfNeeded() {
+ synchronized (this){
+ return txnState.promoteToTakeIfNeeded();
+ }
+ }
+
+ /**
+ * Returns <code>true</code> it this entry has been removed
+ * outside of a transaction, but that removal has not yet been
+ * committed to disk.The thread calling this method should own this
+ * object's lock.
+ */
+ boolean isProvisionallyRemoved() {
+ assert Thread.holdsLock(this);
+ return removePending;
+ }
+
+ /**
+ * Marks this entry as being removed outside of a transaction but
+ * not yet committed to disk. The thread calling this method should
+ * own this object's lock.
+ */
+ void provisionallyRemove() {
+ assert Thread.holdsLock(this);
+ assert !removePending;
+ removePending = true;
+ }
+
+ /**
+ * Called after the removal of a provisionally removed entry has
+ * been committed to disk and the handle has been removed from its
+ * holder. The thread calling this method should own this object's
+ * lock.
+ */
+ void removalComplete() {
+ assert Thread.holdsLock(this);
+
+ if (removePending) {
+ removePending = false;
+ notifyAll();
+ }
+ }
+
+ /**
+ * If this entry has been marked for removal by a
+ * non-transactional operation, but that operation has not be
+ * yet been committed to disk, block until the operation has been
+ * committed to disk, otherwise return immediately. The
+ * thread calling this method should own this object's lock.
+ */
+ void waitOnCompleteRemoval() throws InterruptedException {
+ assert Thread.holdsLock(this);
+ while (removePending) {
+ wait();
+ }
+ }
+
+ /**************************************************
+ * Methods required by the Transactable interface
+ **************************************************/
+ public synchronized int prepare(TransactableMgr mgr,
+ OutriggerServerImpl space)
+ {
+ if (txnState == null)
+ throw new IllegalStateException("Can't prepare an entry not " +
+ "involved in a transaction");
+ final int rslt = txnState.prepare(mgr, space, this);
+ if (txnState.empty())
+ txnState = null;
+
+ return rslt;
+ }
+
+ public synchronized void abort(TransactableMgr mgr,
+ OutriggerServerImpl space)
+ {
+ if (txnState == null)
+ throw new IllegalStateException("Can't abort an entry not " +
+ "involved in a transaction");
+ final boolean last = txnState.abort(mgr, space, this);
+ if (last)
+ txnState = null;
+ }
+
+ public synchronized void commit(TransactableMgr mgr,
+ OutriggerServerImpl space)
+ {
+ if (txnState == null)
+ throw new IllegalStateException("Can't commit an entry not " +
+ "involved in a transaction");
+
+ final boolean last = txnState.commit(mgr, space, this);
+ if (last)
+ txnState = null;
+ }
+
+ @Override
+ public synchronized boolean removed() {
+ return removed;
+ }
+
+ public synchronized boolean remove() {
+ if (!removed) removed = super.remove();
+ return removed;
+ }
+}