Skip to content

Commit

Permalink
HTTPCLIENT-2284: internal cache storage improvements (#478)
Browse files Browse the repository at this point in the history
  • Loading branch information
ok2c committed Aug 28, 2023
1 parent 5eea636 commit a6a3516
Show file tree
Hide file tree
Showing 5 changed files with 197 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,13 @@
@Contract(threading = ThreadingBehavior.SAFE)
public class BasicHttpCacheStorage implements HttpCacheStorage {

private final CacheMap entries;
private final InternalCacheStorage entries;

private final ReentrantLock lock;

public BasicHttpCacheStorage(final CacheConfig config) {
super();
this.entries = new CacheMap(config.getMaxCacheEntries());
this.entries = new InternalCacheStorage(config.getMaxCacheEntries(), null);
this.lock = new ReentrantLock();
}

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* ====================================================================
* 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.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.hc.client5.http.impl.cache;

import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import java.util.function.Consumer;

import org.apache.hc.client5.http.cache.HttpCacheEntry;
import org.apache.hc.client5.http.cache.HttpCacheStorageEntry;
import org.apache.hc.core5.annotation.Internal;

@Internal
final public class InternalCacheStorage {

private final Map<String, HttpCacheEntry> map;
private final Queue<HttpCacheStorageEntry> evictionQueue;
private final Consumer<HttpCacheStorageEntry> evictionCallback;

public InternalCacheStorage(final int maxEntries, final Consumer<HttpCacheStorageEntry> evictionCallback) {
this.evictionCallback = evictionCallback;
this.map = new LinkedHashMap<String, HttpCacheEntry>(20, 0.75f, true) {

@Override
protected boolean removeEldestEntry(final Map.Entry<String, HttpCacheEntry> eldest) {
if (size() > maxEntries) {
if (evictionCallback != null) {
evictionQueue.add(new HttpCacheStorageEntry(eldest.getKey(), eldest.getValue()));
}
return true;
} else {
return false;
}
}

};
this.evictionQueue = new LinkedList<>();
}

public InternalCacheStorage(final int maxEntries) {
this(maxEntries, null);
}

public InternalCacheStorage() {
this(Integer.MAX_VALUE, null);
}

public void put(final String key, final HttpCacheEntry entry) {
map.put(key, entry);
HttpCacheStorageEntry evicted;
while ((evicted = evictionQueue.poll()) != null) {
if (evictionCallback != null) {
evictionCallback.accept(evicted);
}
}
}

public HttpCacheEntry get(final String key) {
return map.get(key);
}

public HttpCacheEntry remove(final String key) {
return map.remove(key);
}

public void clear() {
map.clear();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
@Contract(threading = ThreadingBehavior.SAFE)
public class ManagedHttpCacheStorage implements HttpCacheStorage, Closeable {

private final CacheMap entries;
private final InternalCacheStorage entries;
private final ReferenceQueue<HttpCacheEntry> morque;
private final Set<ResourceReference> resources;
private final AtomicBoolean active;
Expand All @@ -87,7 +87,7 @@ public class ManagedHttpCacheStorage implements HttpCacheStorage, Closeable {

public ManagedHttpCacheStorage(final CacheConfig config) {
super();
this.entries = new CacheMap(config.getMaxCacheEntries());
this.entries = new InternalCacheStorage(config.getMaxCacheEntries(), null);
this.morque = new ReferenceQueue<>();
this.resources = new HashSet<>();
this.active = new AtomicBoolean(true);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* ====================================================================
* 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.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.hc.client5.http.impl.cache;

import java.util.LinkedList;
import java.util.Queue;

import org.apache.hc.client5.http.cache.HttpCacheEntry;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class TestInternalCacheStorage {

@Test
public void testCacheBasics() {
final InternalCacheStorage storage = new InternalCacheStorage();
final String key1 = "some-key-1";
Assertions.assertNull(storage.get(key1));
Assertions.assertNull(storage.remove(key1));
final HttpCacheEntry entry1 = HttpTestUtils.makeCacheEntry();
storage.put(key1, entry1);
Assertions.assertSame(entry1, storage.get(key1));
Assertions.assertSame(entry1, storage.remove(key1));
Assertions.assertNull(storage.get(key1));
Assertions.assertNull(storage.remove(key1));
final String key2 = "some-key-2";
final HttpCacheEntry entry2 = HttpTestUtils.makeCacheEntry();
final String key3 = "some-key-3";
final HttpCacheEntry entry3 = HttpTestUtils.makeCacheEntry();
storage.put(key2, entry2);
storage.put(key3, entry3);
Assertions.assertSame(entry2, storage.get(key2));
Assertions.assertSame(entry3, storage.get(key3));
storage.clear();
Assertions.assertNull(storage.get(key2));
Assertions.assertNull(storage.get(key3));
}

@Test
public void testCacheEviction() {
final Queue<HttpCacheEntry> evictedEntries = new LinkedList<>();
final InternalCacheStorage storage = new InternalCacheStorage(2, e -> evictedEntries.add(e.getContent()));
final String key1 = "some-key-1";
final String key2 = "some-key-2";
final String key3 = "some-key-3";
final String key4 = "some-key-4";
final HttpCacheEntry entry1 = HttpTestUtils.makeCacheEntry();
final HttpCacheEntry entry2 = HttpTestUtils.makeCacheEntry();
final HttpCacheEntry entry3 = HttpTestUtils.makeCacheEntry();
final HttpCacheEntry entry4 = HttpTestUtils.makeCacheEntry();

storage.put(key1, entry1);
storage.put(key2, entry2);
storage.put(key3, entry3);
storage.put(key4, entry4);
Assertions.assertSame(entry1, evictedEntries.poll());
Assertions.assertSame(entry2, evictedEntries.poll());
Assertions.assertNull(evictedEntries.poll());

storage.clear();
storage.put(key1, entry1);
storage.put(key2, entry2);
storage.get(key1);
storage.put(key3, entry3);
storage.get(key1);
storage.put(key4, entry4);

Assertions.assertSame(entry2, evictedEntries.poll());
Assertions.assertSame(entry3, evictedEntries.poll());
Assertions.assertNull(evictedEntries.poll());
}

}

0 comments on commit a6a3516

Please sign in to comment.