aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/test/java/com/google/devtools/build
diff options
context:
space:
mode:
authorGravatar Mark Schaller <mschaller@google.com>2015-04-24 15:48:53 +0000
committerGravatar Han-Wen Nienhuys <hanwen@google.com>2015-04-27 18:48:14 +0000
commit906f255982742a373890437f086c08feab980349 (patch)
treefe0acb92e405baf5bdde519fd3559f33c37a394f /src/test/java/com/google/devtools/build
parentce4717a9e720e75b70fb000b040547d7dc3b0216 (diff)
Make SkyKey cached hash code transient
SkyKey argument hashcodes are not stable, because they're composed of values whose hashcodes may not be stable, such as Java enums. Therefore a SkyKey's own hashcode isn't stable. And this is fine, but if we try to serialize and then deserialize the SkyKey with its cached hashcode, the deserialized SkyKey's cached hashcode won't match a normally constructed SkyKey, despite them being equal. Because a SkyKey will deserialize with a default value of 0 for its cached hashcode, this change also introduces a transient boolean guard to note whether the correct hashcode has been calculated and cached. -- MOS_MIGRATED_REVID=91985674
Diffstat (limited to 'src/test/java/com/google/devtools/build')
-rw-r--r--src/test/java/com/google/devtools/build/skyframe/SkyKeyTest.java88
1 files changed, 88 insertions, 0 deletions
diff --git a/src/test/java/com/google/devtools/build/skyframe/SkyKeyTest.java b/src/test/java/com/google/devtools/build/skyframe/SkyKeyTest.java
new file mode 100644
index 0000000000..0eeed132c2
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/skyframe/SkyKeyTest.java
@@ -0,0 +1,88 @@
+// Copyright 2015 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 static com.google.common.truth.Truth.assertThat;
+
+import com.google.devtools.build.lib.testutil.TestUtils;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.Serializable;
+
+/**
+ * Unit test for the SkyKey class, checking hash code transience logic.
+ */
+@RunWith(JUnit4.class)
+public class SkyKeyTest {
+
+ @Test
+ public void testHashCodeTransience() throws Exception {
+ // Given a freshly constructed HashCodeSpy object,
+ HashCodeSpy hashCodeSpy = new HashCodeSpy();
+ assertThat(hashCodeSpy.getNumberOfTimesHashCodeCalled()).isEqualTo(0);
+
+ // When a SkyKey is constructed with that HashCodeSpy as its argument,
+ SkyKey originalKey = new SkyKey(new SkyFunctionName("TEMP", true), hashCodeSpy);
+
+ // Then the HashCodeSpy reports that its hashcode method was called once.
+ assertThat(hashCodeSpy.getNumberOfTimesHashCodeCalled()).isEqualTo(1);
+
+
+ // When the SkyKey's hashCode method is called,
+ originalKey.hashCode();
+
+ // Then the spy's hashCode method isn't called, because the SkyKey's hashCode was cached.
+ assertThat(hashCodeSpy.getNumberOfTimesHashCodeCalled()).isEqualTo(1);
+
+
+ // When that SkyKey is serialized and then deserialized,
+ SkyKey newKey = (SkyKey) TestUtils.deserializeObject(TestUtils.serializeObject(originalKey));
+
+ // Then the new SkyKey's HashCodeSpy has not had its hashCode method called.
+ HashCodeSpy spyInNewKey = (HashCodeSpy) newKey.argument();
+ assertThat(spyInNewKey.getNumberOfTimesHashCodeCalled()).isEqualTo(0);
+
+
+ // When the new SkyKey's hashCode method is called once,
+ newKey.hashCode();
+
+ // Then the new SkyKey's spy's hashCode method gets called.
+ assertThat(spyInNewKey.getNumberOfTimesHashCodeCalled()).isEqualTo(1);
+
+
+ // When the new SkyKey's hashCode method is called a second time,
+ newKey.hashCode();
+
+ // Then the new SkyKey's spy's hashCOde isn't called a second time, because the SkyKey's
+ // hashCode was cached.
+ assertThat(spyInNewKey.getNumberOfTimesHashCodeCalled()).isEqualTo(1);
+ }
+
+ private static class HashCodeSpy implements Serializable {
+ private transient int numberOfTimesHashCodeCalled;
+
+ public int getNumberOfTimesHashCodeCalled() {
+ return numberOfTimesHashCodeCalled;
+ }
+
+ @Override
+ public int hashCode() {
+ numberOfTimesHashCodeCalled++;
+ return 42;
+ }
+ }
+}