Coverage Summary for Class: BlocksBloomStore (co.rsk.logfilter)

Class Method, % Line, %
BlocksBloomStore 7.1% (1/14) 2.4% (1/42)
BlocksBloomStore$MockitoMock$71423407
BlocksBloomStore$MockitoMock$71423407$auxiliary$1Wm14qUu
BlocksBloomStore$MockitoMock$71423407$auxiliary$2jamLxtT
BlocksBloomStore$MockitoMock$71423407$auxiliary$5OyDQeWU
BlocksBloomStore$MockitoMock$71423407$auxiliary$6Lcq8nY9
BlocksBloomStore$MockitoMock$71423407$auxiliary$aKcoMpkd
BlocksBloomStore$MockitoMock$71423407$auxiliary$CiV01KOZ
BlocksBloomStore$MockitoMock$71423407$auxiliary$CRdoShYC
BlocksBloomStore$MockitoMock$71423407$auxiliary$jmBjv7QH
BlocksBloomStore$MockitoMock$71423407$auxiliary$THjJnmul
BlocksBloomStore$MockitoMock$71423407$auxiliary$WQXGOLGg
BlocksBloomStore$MockitoMock$71423407$auxiliary$XfTTVyqd
Total 7.1% (1/14) 2.4% (1/42)


1 /* 2  * This file is part of RskJ 3  * Copyright (C) 2017 RSK Labs Ltd. 4  * (derived from ethereumJ library, Copyright (c) 2016 <ether.camp>) 5  * 6  * This program is free software: you can redistribute it and/or modify 7  * it under the terms of the GNU Lesser General Public License as published by 8  * the Free Software Foundation, either version 3 of the License, or 9  * (at your option) any later version. 10  * 11  * This program is distributed in the hope that it will be useful, 12  * but WITHOUT ANY WARRANTY; without even the implied warranty of 13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14  * GNU Lesser General Public License for more details. 15  * 16  * You should have received a copy of the GNU Lesser General Public License 17  * along with this program. If not, see <http://www.gnu.org/licenses/>. 18  */ 19  20 package co.rsk.logfilter; 21  22 import org.ethereum.datasource.KeyValueDataSource; 23 import org.ethereum.vm.DataWord; 24 import org.slf4j.Logger; 25 import org.slf4j.LoggerFactory; 26  27 import java.util.HashMap; 28 import java.util.Map; 29  30 /** 31  * Block blooms store 32  * 33  * It saves and retrieves coalesced bloom filters 34  * 35  * Each record represents a range of blocks 36  * 37  * The key is the block number of the first block in the range 38  * 39  * It keeps also an in-memory cache of those records 40  * 41  * Created by ajlopez on 05/02/2019. 42  */ 43 public class BlocksBloomStore { 44  private static final Logger logger = LoggerFactory.getLogger("blooms"); 45  46  private final int noBlocks; 47  private final int noConfirmations; 48  private final Map<Long, BlocksBloom> blocksBloomCache = new HashMap<>(); 49  private final KeyValueDataSource dataSource; 50  51  public BlocksBloomStore(int noBlocks, int noConfirmations, KeyValueDataSource dataSource) { 52  this.noBlocks = noBlocks; 53  this.noConfirmations = noConfirmations; 54  this.dataSource = dataSource; 55  } 56  57  /** 58  * Returns if a block number is included in one of the 59  * group records (in persistence store or in cache) 60  * 61  * @param blockNumber block number to query 62  * @return true if the block number is in some record, false if not 63  */ 64  public synchronized boolean hasBlockNumber(long blockNumber) { 65  long key = this.firstNumberInRange(blockNumber); 66  67  return hasBlockNumberInCache(key) 68  || hasBlockNumberInStore(key); 69  } 70  71  private boolean hasBlockNumberInStore(long key) { 72  return this.dataSource != null && this.dataSource.get(longToKey(key)) != null; 73  } 74  75  private boolean hasBlockNumberInCache(long key) { 76  return this.blocksBloomCache.containsKey(key); 77  } 78  79  /** 80  * Retrieves the coalesced blooms record that contains 81  * the bloom filter associated with the block corresponding 82  * to the provided block number 83  * 84  * It retrieves the record from cache or from store 85  * 86  * If it is found in the store, it is added to the cache 87  * 88  * @param number 89  * @return the BlocksBloom that contains that block number, null if absent 90  */ 91  public synchronized BlocksBloom getBlocksBloomByNumber(long number) { 92  long key = firstNumberInRange(number); 93  94  BlocksBloom blocksBloom = this.blocksBloomCache.get(key); 95  96  if (blocksBloom != null) { 97  return blocksBloom; 98  } 99  100  if (this.dataSource == null) { 101  return null; 102  } 103  104  byte[] data = this.dataSource.get(longToKey(key)); 105  106  if (data == null) { 107  return null; 108  } 109  110  blocksBloom = BlocksBloomEncoder.decode(data); 111  112  this.blocksBloomCache.put(key, blocksBloom); 113  114  return blocksBloom; 115  } 116  117  /** 118  * Save the group bloom filter that contains the block blooms 119  * in a range. The first block number in that range is used as the key 120  * 121  * @param blocksBloom the record to add 122  */ 123  public synchronized void addBlocksBloom(BlocksBloom blocksBloom) { 124  logger.trace("set blocks bloom: height {}", blocksBloom.fromBlock()); 125  126  this.blocksBloomCache.put(blocksBloom.fromBlock(), blocksBloom); 127  128  if (this.dataSource != null) { 129  this.dataSource.put(longToKey(blocksBloom.fromBlock()), BlocksBloomEncoder.encode(blocksBloom)); 130  } 131  } 132  133  public long firstNumberInRange(long number) { 134  return number - (number % this.noBlocks); 135  } 136  137  public long lastNumberInRange(long number) { 138  return firstNumberInRange(number) + this.noBlocks - 1; 139  } 140  141  public int getNoBlocks() { 142  return this.noBlocks; 143  } 144  145  public int getNoConfirmations() { return this.noConfirmations; } 146  147  /** 148  * Converts a long number to its byte array representation 149  * 150  * The byte array is normalized to remove the leading zeroes 151  * 152  * If zero value is provided, a zero-length byte array is returned 153  * 154  * @param value number to convert 155  * @return bytes representing the value (0 == empty array) 156  */ 157  public static byte[] longToKey(long value) { 158  if (value == 0) { 159  return new byte[0]; 160  } 161  162  return DataWord.valueOf(value).getByteArrayForStorage(); 163  } 164  165  public void flush() { 166  if (this.dataSource != null) { 167  this.dataSource.flush(); 168  } 169  } 170  171  public void close() { 172  if (this.dataSource != null) { 173  this.dataSource.close(); 174  } 175  } 176 }