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 }