private void evict0() {
            // TODO: avoid awake more tasks than necessary
            long expiredTimestamp = time.milliseconds() - DATA_TTL;
            while (true) {
                Map.Entry<DataBlockGroupKey, DataBlock> entry;
                entry = lru.peek();
                if (entry == null) {
                    break;
                }
                DataBlockGroupKey key = entry.getKey();
                DataBlock dataBlock = entry.getValue();
                if (!dataBlock.isExpired(expiredTimestamp) && !sizeLimiter.requiredRelease()) {
                    break;
                }
                lru.pop();
                if (blocks.remove(key, dataBlock)) {
                    dataBlock.free();
                    StorageOperationStats.getInstance().blockCacheBlockEvictThroughput.add(MetricsLevel.INFO, dataBlock.dataBlockIndex().size());
                } else {
                    LOGGER.error("[BUG] duplicated free data block {}", dataBlock);
                }
            }
        }
Get the data block from cache.
<p>
Note: the data block should invoke the {@link DataBlock#release()} after using.

@param options        the get options
@param objectReader   the object reader could be used read the data block when cache misses
@param dataBlockIndex the required data block's index
@return the future of {@link DataBlock}, the future will be completed in the same stream's eventLoop.
s3stream/src/main/java/com/automq/stream/s3/cache/blockcache/DataBlockCache.java