org.gradle.cache.internal.btree.BTreePersistentIndexedCacheTest Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle-api Show documentation
Show all versions of gradle-api Show documentation
Gradle 6.9.1 API redistribution.
/*
* Copyright 2010 the original author or authors.
*
* 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 org.gradle.cache.internal.btree;
import org.gradle.internal.serialize.DefaultSerializer;
import org.gradle.internal.serialize.Serializer;
import org.gradle.test.fixtures.file.TestFile;
import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
public class BTreePersistentIndexedCacheTest {
@Rule
public TestNameTestDirectoryProvider tmpDir = new TestNameTestDirectoryProvider();
private final Serializer stringSerializer = new DefaultSerializer();
private final Serializer integerSerializer = new DefaultSerializer();
private BTreePersistentIndexedCache cache;
private TestFile cacheFile;
@Before
public void setup() {
cacheFile = tmpDir.file("cache.bin");
}
private void createCache() {
cache = new BTreePersistentIndexedCache(cacheFile, stringSerializer, integerSerializer, (short) 4, 100);
}
private void verifyAndCloseCache() {
cache.verify();
cache.close();
}
@Test
public void getReturnsNullWhenEntryDoesNotExist() {
createCache();
assertNull(cache.get("unknown"));
verifyAndCloseCache();
}
@Test
public void persistsAddedEntries() {
createCache();
checkAdds(1, 2, 3, 4, 5);
verifyAndCloseCache();
}
@Test
public void persistsAddedEntriesInReverseOrder() {
createCache();
checkAdds(5, 4, 3, 2, 1);
verifyAndCloseCache();
}
@Test
public void persistsAddedEntriesOverMultipleIndexBlocks() {
createCache();
checkAdds(3, 2, 11, 5, 7, 1, 10, 8, 9, 4, 6, 0);
verifyAndCloseCache();
}
@Test
public void persistsUpdates() {
createCache();
checkUpdates(3, 2, 11, 5, 7, 1, 10, 8, 9, 4, 6, 0);
verifyAndCloseCache();
}
@Test
public void handlesUpdatesWhenBlockSizeDecreases() {
BTreePersistentIndexedCache> cache = new BTreePersistentIndexedCache>(tmpDir.file("listcache.bin"), stringSerializer, new DefaultSerializer>(), (short) 4, 100);
List values = Arrays.asList(3, 2, 11, 5, 7, 1, 10, 8, 9, 4, 6, 0);
Map> updated = new LinkedHashMap>();
for (int i = 10; i > 0; i--) {
for (Integer value : values) {
String key = String.format("key_%d", value);
List newValue = new ArrayList(i);
for (int j = 0; j < i * 2; j++) {
newValue.add(j);
}
cache.put(key, newValue);
updated.put(value, newValue);
}
checkListEntries(cache, updated);
}
cache.reset();
checkListEntries(cache, updated);
cache.verify();
cache.close();
}
private void checkListEntries(BTreePersistentIndexedCache> cache, Map> updated) {
for (Map.Entry> entry : updated.entrySet()) {
String key = String.format("key_%d", entry.getKey());
assertThat(cache.get(key), equalTo(entry.getValue()));
}
}
@Test
public void handlesUpdatesWhenBlockSizeIncreases() {
BTreePersistentIndexedCache> cache = new BTreePersistentIndexedCache>(tmpDir.file("listcache.bin"), stringSerializer, new DefaultSerializer>(), (short) 4, 100);
List values = Arrays.asList(3, 2, 11, 5, 7, 1, 10, 8, 9, 4, 6, 0);
Map> updated = new LinkedHashMap>();
for (int i = 1; i < 10; i++) {
for (Integer value : values) {
String key = String.format("key_%d", value);
List newValue = new ArrayList(i);
for (int j = 0; j < i * 2; j++) {
newValue.add(j);
}
cache.put(key, newValue);
updated.put(value, newValue);
}
checkListEntries(cache, updated);
}
cache.reset();
checkListEntries(cache, updated);
cache.verify();
cache.close();
}
@Test
public void persistsAddedEntriesAfterReopen() {
createCache();
checkAdds(1, 2, 3, 4);
cache.reset();
checkAdds(5, 6, 7, 8);
verifyAndCloseCache();
}
@Test
public void persistsReplacedEntries() {
createCache();
cache.put("key_1", 1);
cache.put("key_2", 2);
cache.put("key_3", 3);
cache.put("key_4", 4);
cache.put("key_5", 5);
cache.put("key_1", 1);
cache.put("key_4", 12);
assertThat(cache.get("key_1"), equalTo(1));
assertThat(cache.get("key_2"), equalTo(2));
assertThat(cache.get("key_3"), equalTo(3));
assertThat(cache.get("key_4"), equalTo(12));
assertThat(cache.get("key_5"), equalTo(5));
cache.reset();
assertThat(cache.get("key_1"), equalTo(1));
assertThat(cache.get("key_2"), equalTo(2));
assertThat(cache.get("key_3"), equalTo(3));
assertThat(cache.get("key_4"), equalTo(12));
assertThat(cache.get("key_5"), equalTo(5));
verifyAndCloseCache();
}
@Test
public void reusesEmptySpaceWhenPuttingEntries() {
BTreePersistentIndexedCache cache = new BTreePersistentIndexedCache(cacheFile, stringSerializer, stringSerializer, (short) 4, 100);
cache.put("key_1", "abcd");
cache.put("key_2", "abcd");
cache.put("key_3", "abcd");
cache.put("key_4", "abcd");
cache.put("key_5", "abcd");
long len = cacheFile.length();
assertThat(len, greaterThan(0L));
cache.put("key_1", "1234");
assertThat(cacheFile.length(), equalTo(len));
cache.remove("key_1");
cache.put("key_new", "a1b2");
assertThat(cacheFile.length(), equalTo(len));
cache.put("key_new", "longer value");
assertThat(cacheFile.length(), greaterThan(len));
len = cacheFile.length();
cache.put("key_1", "1234");
assertThat(cacheFile.length(), equalTo(len));
cache.close();
}
@Test
public void canHandleLargeNumberOfEntries() {
createCache();
int count = 2000;
List values = new ArrayList();
for (int i = 0; i < count; i++) {
values.add(i);
}
checkAddsAndRemoves(null, values);
long len = cacheFile.length();
checkAddsAndRemoves(Collections.reverseOrder(), values);
// need to make this better
assertThat(cacheFile.length(), lessThan((long)(1.4 * len)));
checkAdds(values);
// need to make this better
assertThat(cacheFile.length(), lessThan((long) (1.4 * 1.4 * len)));
cache.close();
}
@Test
public void persistsRemovalOfEntries() {
createCache();
checkAddsAndRemoves(1, 2, 3, 4, 5);
verifyAndCloseCache();
}
@Test
public void persistsRemovalOfEntriesInReverse() {
createCache();
checkAddsAndRemoves(Collections.reverseOrder(), 1, 2, 3, 4, 5);
verifyAndCloseCache();
}
@Test
public void persistsRemovalOfEntriesOverMultipleIndexBlocks() {
createCache();
checkAddsAndRemoves(4, 12, 9, 1, 3, 10, 11, 7, 8, 2, 5, 6);
verifyAndCloseCache();
}
@Test
public void removalRedistributesRemainingEntriesWithLeftSibling() {
createCache();
// Ends up with: 1 2 3 -> 4 <- 5 6
checkAdds(1, 2, 5, 6, 4, 3);
cache.verify();
cache.remove("key_5");
verifyAndCloseCache();
}
@Test
public void removalMergesRemainingEntriesIntoLeftSibling() {
createCache();
// Ends up with: 1 2 -> 3 <- 4 5
checkAdds(1, 2, 4, 5, 3);
cache.verify();
cache.remove("key_4");
verifyAndCloseCache();
}
@Test
public void removalRedistributesRemainingEntriesWithRightSibling() {
createCache();
// Ends up with: 1 2 -> 3 <- 4 5 6
checkAdds(1, 2, 4, 5, 3, 6);
cache.verify();
cache.remove("key_2");
verifyAndCloseCache();
}
@Test
public void removalMergesRemainingEntriesIntoRightSibling() {
createCache();
// Ends up with: 1 2 -> 3 <- 4 5
checkAdds(1, 2, 4, 5, 3);
cache.verify();
cache.remove("key_2");
verifyAndCloseCache();
}
@Test
public void handlesOpeningACacheFileThatIsBadlyFormed() throws IOException {
cacheFile.createNewFile();
cacheFile.write("some junk");
BTreePersistentIndexedCache cache = new BTreePersistentIndexedCache(cacheFile, stringSerializer, integerSerializer);
assertNull(cache.get("key_1"));
cache.put("key_1", 99);
cache.reset();
assertThat(cache.get("key_1"), equalTo(99));
cache.verify();
cache.close();
}
@Test
public void handlesOpeningATruncatedCacheFile() throws IOException {
BTreePersistentIndexedCache cache = new BTreePersistentIndexedCache(cacheFile, stringSerializer, integerSerializer);
assertNull(cache.get("key_1"));
cache.put("key_1", 99);
RandomAccessFile file = new RandomAccessFile(cacheFile, "rw");
file.setLength(file.length() - 10);
file.close();
cache.reset();
assertNull(cache.get("key_1"));
cache.verify();
cache.close();
}
@Test
public void canUseFileAsKey() {
BTreePersistentIndexedCache cache = new BTreePersistentIndexedCache(cacheFile, new DefaultSerializer(), integerSerializer);
cache.put(new File("file"), 1);
cache.put(new File("dir/file"), 2);
cache.put(new File("File"), 3);
assertThat(cache.get(new File("file")), equalTo(1));
assertThat(cache.get(new File("dir/file")), equalTo(2));
assertThat(cache.get(new File("File")), equalTo(3));
cache.close();
}
@Test
public void handlesKeysWithSameHashCode() {
createCache();
String key1 = new String(new byte[]{2, 31});
String key2 = new String(new byte[]{1, 62});
cache.put(key1, 1);
cache.put(key2, 2);
assertThat(cache.get(key1), equalTo(1));
assertThat(cache.get(key2), equalTo(2));
cache.close();
}
private void checkAdds(Integer... values) {
checkAdds(Arrays.asList(values));
}
private Map checkAdds(Iterable values) {
Map added = new LinkedHashMap();
for (Integer value : values) {
String key = String.format("key_%d", value);
cache.put(key, value);
added.put(String.format("key_%d", value), value);
}
for (Map.Entry entry : added.entrySet()) {
assertThat(cache.get(entry.getKey()), equalTo(entry.getValue()));
}
cache.reset();
for (Map.Entry entry : added.entrySet()) {
assertThat(cache.get(entry.getKey()), equalTo(entry.getValue()));
}
return added;
}
private void checkUpdates(Integer... values) {
checkUpdates(Arrays.asList(values));
}
private Map checkUpdates(Iterable values) {
Map updated = new LinkedHashMap();
for (int i = 0; i < 10; i++) {
for (Integer value : values) {
String key = String.format("key_%d", value);
int newValue = value + (i * 100);
cache.put(key, newValue);
updated.put(value, newValue);
}
for (Map.Entry entry : updated.entrySet()) {
String key = String.format("key_%d", entry.getKey());
assertThat(cache.get(key), equalTo(entry.getValue()));
}
}
cache.reset();
for (Map.Entry entry : updated.entrySet()) {
String key = String.format("key_%d", entry.getKey());
assertThat(cache.get(key), equalTo(entry.getValue()));
}
return updated;
}
private void checkAddsAndRemoves(Integer... values) {
checkAddsAndRemoves(null, values);
}
private void checkAddsAndRemoves(Comparator comparator, Integer... values) {
checkAddsAndRemoves(comparator, Arrays.asList(values));
}
private void checkAddsAndRemoves(Comparator comparator, Collection values) {
checkAdds(values);
List deleteValues = new ArrayList(values);
Collections.sort(deleteValues, comparator);
for (Integer value : deleteValues) {
String key = String.format("key_%d", value);
assertThat(cache.get(key), notNullValue());
cache.remove(key);
assertThat(cache.get(key), nullValue());
}
cache.reset();
cache.verify();
for (Integer value : deleteValues) {
String key = String.format("key_%d", value);
assertThat(cache.get(key), nullValue());
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy