aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/test/java/com/google/devtools/build/skyframe/NotifyingInMemoryGraph.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/java/com/google/devtools/build/skyframe/NotifyingInMemoryGraph.java')
-rw-r--r--src/test/java/com/google/devtools/build/skyframe/NotifyingInMemoryGraph.java128
1 files changed, 128 insertions, 0 deletions
diff --git a/src/test/java/com/google/devtools/build/skyframe/NotifyingInMemoryGraph.java b/src/test/java/com/google/devtools/build/skyframe/NotifyingInMemoryGraph.java
new file mode 100644
index 0000000000..aa88278e78
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/skyframe/NotifyingInMemoryGraph.java
@@ -0,0 +1,128 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.skyframe;
+
+import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
+import com.google.devtools.build.lib.util.Pair;
+
+import java.util.Set;
+
+/**
+ * Class that allows clients to be notified on each access of the graph. Clients can simply track
+ * accesses, or they can block to achieve desired synchronization.
+ */
+public class NotifyingInMemoryGraph extends InMemoryGraph {
+ private final Listener graphListener;
+
+ public NotifyingInMemoryGraph(Listener graphListener) {
+ this.graphListener = graphListener;
+ }
+
+ @Override
+ public NodeEntry createIfAbsent(SkyKey key) {
+ graphListener.accept(key, EventType.CREATE_IF_ABSENT, Order.BEFORE, null);
+ NodeEntry newval = getEntry(key);
+ NodeEntry oldval = getNodeMap().putIfAbsent(key, newval);
+ return oldval == null ? newval : oldval;
+ }
+
+ // Subclasses should override if they wish to subclass NotifyingNodeEntry.
+ protected NotifyingNodeEntry getEntry(SkyKey key) {
+ return new NotifyingNodeEntry(key);
+ }
+
+ /** Receiver to be informed when an event for a given key occurs. */
+ public interface Listener {
+ @ThreadSafe
+ void accept(SkyKey key, EventType type, Order order, Object context);
+
+ public static Listener NULL_LISTENER = new Listener() {
+ @Override
+ public void accept(SkyKey key, EventType type, Order order, Object context) {}
+ };
+ }
+
+ /**
+ * Graph/value entry events that the receiver can be informed of. When writing tests, feel free to
+ * add additional events here if needed.
+ */
+ public enum EventType {
+ CREATE_IF_ABSENT,
+ ADD_REVERSE_DEP,
+ SIGNAL,
+ SET_VALUE,
+ MARK_DIRTY,
+ IS_CHANGED,
+ IS_DIRTY
+ }
+
+ public enum Order {
+ BEFORE,
+ AFTER
+ }
+
+ protected class NotifyingNodeEntry extends NodeEntry {
+ private final SkyKey myKey;
+
+ protected NotifyingNodeEntry(SkyKey key) {
+ myKey = key;
+ }
+
+ // Note that these methods are not synchronized. Necessary synchronization happens when calling
+ // the super() methods.
+ @Override
+ DependencyState addReverseDepAndCheckIfDone(SkyKey reverseDep) {
+ graphListener.accept(myKey, EventType.ADD_REVERSE_DEP, Order.BEFORE, reverseDep);
+ DependencyState result = super.addReverseDepAndCheckIfDone(reverseDep);
+ graphListener.accept(myKey, EventType.ADD_REVERSE_DEP, Order.AFTER, reverseDep);
+ return result;
+ }
+
+ @Override
+ boolean signalDep(Version childVersion) {
+ graphListener.accept(myKey, EventType.SIGNAL, Order.BEFORE, childVersion);
+ boolean result = super.signalDep(childVersion);
+ graphListener.accept(myKey, EventType.SIGNAL, Order.AFTER, childVersion);
+ return result;
+ }
+
+ @Override
+ public Set<SkyKey> setValue(SkyValue value, Version version) {
+ graphListener.accept(myKey, EventType.SET_VALUE, Order.BEFORE, value);
+ Set<SkyKey> result = super.setValue(value, version);
+ graphListener.accept(myKey, EventType.SET_VALUE, Order.AFTER, value);
+ return result;
+ }
+
+ @Override
+ Pair<? extends Iterable<SkyKey>, ? extends SkyValue> markDirty(boolean isChanged) {
+ graphListener.accept(myKey, EventType.MARK_DIRTY, Order.BEFORE, isChanged);
+ Pair<? extends Iterable<SkyKey>, ? extends SkyValue> result = super.markDirty(isChanged);
+ graphListener.accept(myKey, EventType.MARK_DIRTY, Order.AFTER, isChanged);
+ return result;
+ }
+
+ @Override
+ boolean isChanged() {
+ graphListener.accept(myKey, EventType.IS_CHANGED, Order.BEFORE, this);
+ return super.isChanged();
+ }
+
+ @Override
+ public boolean isDirty() {
+ graphListener.accept(myKey, EventType.IS_DIRTY, Order.BEFORE, this);
+ return super.isDirty();
+ }
+ }
+}