diff options
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.java | 128 |
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(); + } + } +} |