diff --git a/server/src/main/java/com/hedera/block/server/Server.java b/server/src/main/java/com/hedera/block/server/Server.java index 9519c0986..00cb25b23 100644 --- a/server/src/main/java/com/hedera/block/server/Server.java +++ b/server/src/main/java/com/hedera/block/server/Server.java @@ -19,8 +19,6 @@ import com.hedera.block.protos.BlockStreamServiceGrpcProto; import com.hedera.block.server.mediator.LiveStreamMediatorImpl; import com.hedera.block.server.persistence.WriteThroughCacheHandler; -import com.hedera.block.server.persistence.cache.BlockCache; -import com.hedera.block.server.persistence.cache.LRUCache; import com.hedera.block.server.persistence.storage.BlockStorage; import com.hedera.block.server.persistence.storage.FileSystemBlockStorage; import io.grpc.stub.ServerCalls; @@ -63,9 +61,8 @@ public static void main(final String[] args) { // Initialize the block storage, cache, and service final BlockStorage blockStorage = new FileSystemBlockStorage(BLOCKNODE_STORAGE_ROOT_PATH_KEY, config); - final BlockCache blockCache = new LRUCache(1000); final BlockStreamService blockStreamService = new BlockStreamService(1500, - new LiveStreamMediatorImpl(new WriteThroughCacheHandler(blockStorage, blockCache))); + new LiveStreamMediatorImpl(new WriteThroughCacheHandler(blockStorage))); // Start the web server WebServer.builder() diff --git a/server/src/main/java/com/hedera/block/server/persistence/WriteThroughCacheHandler.java b/server/src/main/java/com/hedera/block/server/persistence/WriteThroughCacheHandler.java index ca0b2bb0f..e59efee49 100644 --- a/server/src/main/java/com/hedera/block/server/persistence/WriteThroughCacheHandler.java +++ b/server/src/main/java/com/hedera/block/server/persistence/WriteThroughCacheHandler.java @@ -17,7 +17,6 @@ package com.hedera.block.server.persistence; import com.hedera.block.protos.BlockStreamServiceGrpcProto; -import com.hedera.block.server.persistence.cache.BlockCache; import com.hedera.block.server.persistence.storage.BlockStorage; import java.util.ArrayDeque; @@ -31,18 +30,14 @@ public class WriteThroughCacheHandler implements BlockPersistenceHandler { private final BlockStorage blockStorage; - private final BlockCache blockCache; /** * Constructor for the WriteThroughCacheHandler class. * * @param blockStorage the block storage - * @param blockCache the block cache */ - public WriteThroughCacheHandler(final BlockStorage blockStorage, - final BlockCache blockCache) { + public WriteThroughCacheHandler(final BlockStorage blockStorage) { this.blockStorage = blockStorage; - this.blockCache = blockCache; } /** @@ -56,7 +51,7 @@ public Long persist(final BlockStreamServiceGrpcProto.Block block) { // Write-Through cache blockStorage.write(block); - return blockCache.insert(block); + return block.getId(); } /** @@ -91,15 +86,6 @@ public Queue readRange(final long startBlockI */ @Override public Optional read(final long id) { - - if (blockCache.contains(id)) { - return Optional.of(blockCache.get(id)); - } else { - // Update the cache with the block from storage - Optional block = blockStorage.read(id); - block.ifPresent(blockCache::insert); - - return block; - } + return blockStorage.read(id); } } diff --git a/server/src/main/java/com/hedera/block/server/persistence/cache/BNLinkedHashMap.java b/server/src/main/java/com/hedera/block/server/persistence/cache/BNLinkedHashMap.java deleted file mode 100644 index c05c82420..000000000 --- a/server/src/main/java/com/hedera/block/server/persistence/cache/BNLinkedHashMap.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2024 Hedera Hashgraph, LLC - * - * 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.hedera.block.server.persistence.cache; - -import java.util.LinkedHashMap; -import java.util.Map; - -/** - * A custom implementation of a LinkedHashMap that removes the eldest entry when the size exceeds a - * specified limit. - * - * @param the type of the keys - * @param the type of the values - */ -public class BNLinkedHashMap extends LinkedHashMap { - - private final long maxEntries; - - /** - * Constructor for the BNLinkedHashMap class. - * - * @param maxEntries the maximum number of entries in the map - */ - BNLinkedHashMap(final long maxEntries) { - this.maxEntries = maxEntries; - } - - /** - * Removes the eldest entry when the size exceeds the maximum number of entries. - * - * @param eldest the eldest entry - * @return true if the eldest entry should be removed, false otherwise - */ - @Override - protected boolean removeEldestEntry(final Map.Entry eldest) { - - if (size() > maxEntries) { - return true; - } - - return size() > maxEntries; - } -} diff --git a/server/src/main/java/com/hedera/block/server/persistence/cache/BlockCache.java b/server/src/main/java/com/hedera/block/server/persistence/cache/BlockCache.java deleted file mode 100644 index 67f017562..000000000 --- a/server/src/main/java/com/hedera/block/server/persistence/cache/BlockCache.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2024 Hedera Hashgraph, LLC - * - * 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.hedera.block.server.persistence.cache; - -/** - * The BlockCache interface defines operations to query, store and retrieve blocks from an - * in-memory store to increase throughput and reduce I/O. - * - * @param the type of block to cache - */ -public interface BlockCache { - /** - * Inserts a block into the cache. - * - * @param block the block to insert - * @return the id of the block - */ - Long insert(final V block); - - /** - * Retrieves a block from the cache. - * - * @param id the id of the block to retrieve - * @return the block - */ - V get(final Long id); - - /** - * Checks if the cache contains a block with the given id. - */ - boolean contains(final Long id); -} diff --git a/server/src/main/java/com/hedera/block/server/persistence/cache/LRUCache.java b/server/src/main/java/com/hedera/block/server/persistence/cache/LRUCache.java deleted file mode 100644 index 07cfde04d..000000000 --- a/server/src/main/java/com/hedera/block/server/persistence/cache/LRUCache.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2024 Hedera Hashgraph, LLC - * - * 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.hedera.block.server.persistence.cache; - -import com.hedera.block.protos.BlockStreamServiceGrpcProto; -import jakarta.inject.Singleton; - -import java.util.Collections; -import java.util.Map; - -/** - * An LRU cache implementation which uses a custom LinkedHashMap to store blocks in memory and - * evict the least recently used block when the cache size exceeds a specified limit. - */ -@Singleton -public class LRUCache implements BlockCache { - - private final Map cache; - - /** - * Constructor for the LRUCache class. - * - * @param maxEntries the maximum number of entries in the cache - */ - public LRUCache(final long maxEntries) { - final System.Logger LOGGER = System.getLogger(getClass().getName()); - LOGGER.log(System.Logger.Level.INFO, "Creating LRUCache with maxEntries: " + maxEntries); - - cache = Collections.synchronizedMap(new BNLinkedHashMap<>(maxEntries)); - } - - /** - * Inserts a block into the cache. - * - * @param block the block to insert - * @return the id of the block - */ - @Override - public Long insert(final BlockStreamServiceGrpcProto.Block block) { - final long id = block.getId(); - cache.put(id, block); - return id; - } - - /** - * Retrieves a block from the cache. - * - * @param id the id of the block to retrieve - * @return the block - */ - @Override - public BlockStreamServiceGrpcProto.Block get(final Long id) { - return cache.get(id); - } - - /** - * Checks to see if the cache contains the specified block. - * - * @param id the id of the block to query - */ - @Override - public boolean contains(final Long id) { - return cache.containsKey(id); - } -} diff --git a/server/src/main/java/module-info.java b/server/src/main/java/module-info.java index a7ab48188..c78fae8d4 100644 --- a/server/src/main/java/module-info.java +++ b/server/src/main/java/module-info.java @@ -7,5 +7,4 @@ requires io.helidon.config; requires io.helidon.webserver.grpc; requires io.helidon.webserver; - requires jakarta.inject; } diff --git a/server/src/test/java/com/hedera/block/server/mediator/LiveStreamMediatorImplTest.java b/server/src/test/java/com/hedera/block/server/mediator/LiveStreamMediatorImplTest.java index 2692f69b5..c467bb919 100644 --- a/server/src/test/java/com/hedera/block/server/mediator/LiveStreamMediatorImplTest.java +++ b/server/src/test/java/com/hedera/block/server/mediator/LiveStreamMediatorImplTest.java @@ -20,7 +20,6 @@ import com.hedera.block.protos.BlockStreamServiceGrpcProto; import com.hedera.block.server.consumer.LiveStreamObserver; import com.hedera.block.server.persistence.WriteThroughCacheHandler; -import com.hedera.block.server.persistence.cache.BlockCache; import com.hedera.block.server.persistence.storage.BlockStorage; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -46,14 +45,11 @@ public class LiveStreamMediatorImplTest { @Mock private BlockStorage blockStorage; - @Mock - private BlockCache blockCache; - @Test public void testUnsubscribeEach() { final StreamMediator streamMediator = - new LiveStreamMediatorImpl(new WriteThroughCacheHandler(blockStorage, blockCache)); + new LiveStreamMediatorImpl(new WriteThroughCacheHandler(blockStorage)); // Set up the subscribers streamMediator.subscribe(liveStreamObserver1); @@ -78,24 +74,23 @@ public void testUnsubscribeEach() { public void testMediatorPersistenceWithoutSubscribers() { final StreamMediator streamMediator = - new LiveStreamMediatorImpl(new WriteThroughCacheHandler(blockStorage, blockCache)); + new LiveStreamMediatorImpl(new WriteThroughCacheHandler(blockStorage)); final BlockStreamServiceGrpcProto.Block newBlock = BlockStreamServiceGrpcProto.Block.newBuilder().build(); // Acting as a producer, notify the mediator of a new block streamMediator.notifyAll(newBlock); - // Confirm the block was persisted to storage and cache + // Confirm the block was persisted to storage // even though there are no subscribers verify(blockStorage).write(newBlock); - verify(blockCache).insert(newBlock); } @Test public void testMediatorNotifyAll() { final StreamMediator streamMediator = - new LiveStreamMediatorImpl(new WriteThroughCacheHandler(blockStorage, blockCache)); + new LiveStreamMediatorImpl(new WriteThroughCacheHandler(blockStorage)); // Set up the subscribers streamMediator.subscribe(liveStreamObserver1); @@ -118,7 +113,6 @@ public void testMediatorNotifyAll() { // Confirm the block was persisted to storage and cache verify(blockStorage).write(newBlock); - verify(blockCache).insert(newBlock); } } diff --git a/server/src/test/java/com/hedera/block/server/persistence/RangeTest.java b/server/src/test/java/com/hedera/block/server/persistence/RangeTest.java index 79a06d73e..ef6539a07 100644 --- a/server/src/test/java/com/hedera/block/server/persistence/RangeTest.java +++ b/server/src/test/java/com/hedera/block/server/persistence/RangeTest.java @@ -17,14 +17,10 @@ package com.hedera.block.server.persistence; import com.hedera.block.protos.BlockStreamServiceGrpcProto; -import com.hedera.block.server.persistence.cache.BlockCache; -import com.hedera.block.server.persistence.cache.LRUCache; import com.hedera.block.server.persistence.storage.BlockStorage; import org.junit.jupiter.api.Test; -import java.util.List; -import java.util.Optional; -import java.util.Queue; +import java.util.*; import static com.hedera.block.server.persistence.PersistTestUtils.generateBlocks; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -100,20 +96,26 @@ private static void verifyReadRange( private static BlockPersistenceHandler generateInMemoryTestBlockPersistenceHandler(int maxEntries) { // Mock up a simple, in-memory persistence handler BlockStorage blockStorage = new NoOpTestBlockStorage(); - BlockCache blockCache = new LRUCache(maxEntries); - return new WriteThroughCacheHandler(blockStorage, blockCache); + return new WriteThroughCacheHandler(blockStorage); } private static class NoOpTestBlockStorage implements BlockStorage { + private final Map cache; + + public NoOpTestBlockStorage() { + this.cache = new HashMap<>(); + } + @Override public Optional write(BlockStreamServiceGrpcProto.Block block) { + cache.put(block.getId(), block); return Optional.of(block.getId()); } @Override public Optional read(Long blockId) { - return Optional.empty(); + return Optional.ofNullable(cache.get(blockId)); } } } diff --git a/server/src/test/java/com/hedera/block/server/persistence/WriteThroughCacheHandlerTest.java b/server/src/test/java/com/hedera/block/server/persistence/WriteThroughCacheHandlerTest.java index 30e0f57b0..1ec527584 100644 --- a/server/src/test/java/com/hedera/block/server/persistence/WriteThroughCacheHandlerTest.java +++ b/server/src/test/java/com/hedera/block/server/persistence/WriteThroughCacheHandlerTest.java @@ -17,8 +17,6 @@ package com.hedera.block.server.persistence; import com.hedera.block.protos.BlockStreamServiceGrpcProto; -import com.hedera.block.server.persistence.cache.BlockCache; -import com.hedera.block.server.persistence.cache.LRUCache; import com.hedera.block.server.persistence.storage.BlockStorage; import com.hedera.block.server.persistence.storage.FileSystemBlockStorage; import com.hedera.block.server.util.TestUtils; @@ -68,28 +66,24 @@ public void tearDown() { @Test public void testMaxEntriesGreaterThanBlocks() throws IOException { - int maxEntries = 5; int numOfBlocks = 4; FileSystemBlockStorage blockStorage = new FileSystemBlockStorage(JUNIT, testConfig); - BlockCache blockCache = new LRUCache(maxEntries); - BlockPersistenceHandler blockPersistenceHandler = new WriteThroughCacheHandler(blockStorage, blockCache); + BlockPersistenceHandler blockPersistenceHandler = new WriteThroughCacheHandler(blockStorage); List blocks = generateBlocks(numOfBlocks); - verifyPersistenceHandler(numOfBlocks, maxEntries, blockCache, blocks, blockPersistenceHandler, testPath); + verifyPersistenceHandler(blocks, blockPersistenceHandler, testPath); } @Test public void testMaxEntriesEqualToBlocks() throws IOException { - int maxEntries = 3; int numOfBlocks = 3; FileSystemBlockStorage blockStorage = new FileSystemBlockStorage(JUNIT, testConfig); - BlockCache blockCache = new LRUCache(maxEntries); - BlockPersistenceHandler blockPersistenceHandler = new WriteThroughCacheHandler(blockStorage, blockCache); + BlockPersistenceHandler blockPersistenceHandler = new WriteThroughCacheHandler(blockStorage); List blocks = generateBlocks(numOfBlocks); - verifyPersistenceHandler(numOfBlocks, maxEntries, blockCache, blocks, blockPersistenceHandler, testPath); + verifyPersistenceHandler(blocks, blockPersistenceHandler, testPath); } @Test @@ -98,17 +92,13 @@ public void testMaxEntriesLessThanBlocks() throws IOException { int numOfBlocks = 4; BlockStorage blockStorage = new FileSystemBlockStorage(JUNIT, testConfig); - BlockCache blockCache = new LRUCache(maxEntries); - BlockPersistenceHandler blockPersistenceHandler = new WriteThroughCacheHandler(blockStorage, blockCache); + BlockPersistenceHandler blockPersistenceHandler = new WriteThroughCacheHandler(blockStorage); List blocks = generateBlocks(numOfBlocks); - verifyPersistenceHandler(numOfBlocks, maxEntries, blockCache, blocks, blockPersistenceHandler, testPath); + verifyPersistenceHandler(blocks, blockPersistenceHandler, testPath); } private static void verifyPersistenceHandler( - int numOfBlocks, - int maxEntries, - BlockCache blockCache, List blocks, BlockPersistenceHandler blockPersistenceHandler, Path testPath) throws IOException { @@ -125,9 +115,6 @@ private static void verifyPersistenceHandler( // Verify the block was written to the fs verifyFileExists(blockId, block, testPath); } - - // Verify cache behavior - verifyCache(numOfBlocks, maxEntries, blockCache, blocks); } private static void verifyPersistedBlockIsAccessible(long blockId, BlockPersistenceHandler blockPersistenceHandler) { @@ -150,33 +137,4 @@ private static void verifyFileExists(long blockId, BlockStreamServiceGrpcProto.B assertEquals(block.getValue(), fetchedBlock.getValue()); } } - - private static void verifyCache( - int numOfBlocks, - int maxEntries, - BlockCache blockCache, - List blocks) { - - // Test the cache after all the entries are inserted - for (BlockStreamServiceGrpcProto.Block block : blocks) { - - long blockId = block.getId(); - BlockStreamServiceGrpcProto.Block cachedBlock = blockCache.get(blockId); - - if (numOfBlocks > maxEntries) { - // Calculate if the block should be in the cache or evicted - int maxIndexOutsideCache = numOfBlocks - maxEntries; - if (blockId <= maxIndexOutsideCache) { - // expect a cache miss - assertNull(cachedBlock); - } else { - // expect a cache hit - assertNotNull(cachedBlock); - } - } else { - // All the blocks should be in the cache - assertNotNull(cachedBlock); - } - } - } }