Skip to content

Commit 0085306

Browse files
author
Peter Alfonsi
committed
Addressed Sagar's comments besides new counter/arraylist setup for removing keys
Signed-off-by: Peter Alfonsi <[email protected]>
1 parent 9ef1254 commit 0085306

File tree

5 files changed

+137
-83
lines changed

5 files changed

+137
-83
lines changed

server/src/main/java/org/opensearch/indices/KeyLookupStore.java renamed to server/src/main/java/org/opensearch/common/cache/tier/keystore/KeyLookupStore.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
* GitHub history for details.
3131
*/
3232

33-
package org.opensearch.indices;
33+
package org.opensearch.common.cache.tier.keystore;
3434

3535
/**
3636
* An interface for objects that hold an in-memory record of hashes of keys in the disk cache.
@@ -85,15 +85,14 @@ public interface KeyLookupStore<T> {
8585
* Returns the number of times add() has been run, including unsuccessful attempts.
8686
* @return The number of adding attempts.
8787
*/
88-
int getTotalAdds();
88+
int getAddAttempts();
8989

9090
/**
9191
* Returns the number of times add() has returned false due to a collision.
9292
* @return The number of collisions.
9393
*/
9494
int getCollisions();
9595

96-
9796
/**
9897
* Checks if two values would collide after being transformed by this store's transformation.
9998
* @param value1 The first value to compare.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
*
4+
* The OpenSearch Contributors require contributions made to
5+
* this file be licensed under the Apache-2.0 license or a
6+
* compatible open source license.
7+
*/
8+
9+
package org.opensearch.common.cache.tier.keystore;
10+
11+
import org.opensearch.common.metrics.CounterMetric;
12+
13+
import java.util.concurrent.atomic.AtomicBoolean;
14+
15+
/**
16+
* A stats holder for use in KeyLookupStore implementations.
17+
* Getters should be exposed by the KeyLookupStore which uses it.
18+
*/
19+
public class KeyStoreStats {
20+
protected CounterMetric size;
21+
protected long memSizeCapInBytes;
22+
protected CounterMetric numAddAttempts;
23+
protected CounterMetric numCollisions;
24+
protected boolean guaranteesNoFalseNegatives;
25+
protected final int maxNumEntries;
26+
protected AtomicBoolean atCapacity;
27+
protected CounterMetric numRemovalAttempts;
28+
protected CounterMetric numSuccessfulRemovals;
29+
30+
protected KeyStoreStats(long memSizeCapInBytes, int maxNumEntries) {
31+
this.size = new CounterMetric();
32+
this.numAddAttempts = new CounterMetric();
33+
this.numCollisions = new CounterMetric();
34+
this.memSizeCapInBytes = memSizeCapInBytes;
35+
this.maxNumEntries = maxNumEntries;
36+
this.atCapacity = new AtomicBoolean(false);
37+
this.numRemovalAttempts = new CounterMetric();
38+
this.numSuccessfulRemovals = new CounterMetric();
39+
}
40+
}

server/src/main/java/org/opensearch/indices/RBMIntKeyLookupStore.java renamed to server/src/main/java/org/opensearch/common/cache/tier/keystore/RBMIntKeyLookupStore.java

Lines changed: 52 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,16 @@
3030
* GitHub history for details.
3131
*/
3232

33-
package org.opensearch.indices;
33+
package org.opensearch.common.cache.tier.keystore;
3434

3535
import org.opensearch.common.metrics.CounterMetric;
36-
import org.roaringbitmap.RoaringBitmap;
3736

3837
import java.util.HashSet;
3938
import java.util.concurrent.locks.Lock;
4039
import java.util.concurrent.locks.ReentrantReadWriteLock;
4140

41+
import org.roaringbitmap.RoaringBitmap;
42+
4243
/**
4344
* This class implements KeyLookupStore<Integer> using a roaring bitmap with a modulo applied to values.
4445
* The modulo increases the density of values, which makes RBMs more memory-efficient. The recommended modulo is ~2^28.
@@ -48,39 +49,43 @@
4849
* The store estimates its memory footprint and will stop adding more values once it reaches its memory cap.
4950
*/
5051
public class RBMIntKeyLookupStore implements KeyLookupStore<Integer> {
51-
protected final int modulo;
52-
protected class KeyStoreStats {
53-
protected int size;
54-
protected long memSizeCapInBytes;
55-
protected CounterMetric numAddAttempts;
56-
protected CounterMetric numCollisions;
57-
protected boolean guaranteesNoFalseNegatives;
58-
protected int maxNumEntries;
59-
protected boolean atCapacity;
60-
protected CounterMetric numRemovalAttempts;
61-
protected CounterMetric numSuccessfulRemovals;
62-
protected KeyStoreStats(long memSizeCapInBytes, int maxNumEntries) {
63-
this.size = 0;
64-
this.numAddAttempts = new CounterMetric();
65-
this.numCollisions = new CounterMetric();
66-
this.memSizeCapInBytes = memSizeCapInBytes;
67-
this.maxNumEntries = maxNumEntries;
68-
this.atCapacity = false;
69-
this.numRemovalAttempts = new CounterMetric();
70-
this.numSuccessfulRemovals = new CounterMetric();
52+
/**
53+
* An enum representing modulo values for use in the keystore
54+
*/
55+
public enum KeystoreModuloValue {
56+
NONE(0), // No modulo applied
57+
TWO_TO_THIRTY_ONE((int) Math.pow(2, 31)),
58+
TWO_TO_TWENTY_NINE((int) Math.pow(2, 29)), // recommended value
59+
TWO_TO_TWENTY_EIGHT((int) Math.pow(2, 28)),
60+
TWO_TO_TWENTY_SIX((int) Math.pow(2, 26));
61+
62+
private final int value;
63+
64+
private KeystoreModuloValue(int value) {
65+
this.value = value;
66+
}
67+
68+
public int getValue() {
69+
return this.value;
7170
}
7271
}
7372

74-
protected KeyStoreStats stats;
73+
protected final int modulo;
74+
KeyStoreStats stats;
7575
protected RoaringBitmap rbm;
7676
private HashSet<Integer> collidedInts;
7777
protected RBMSizeEstimator sizeEstimator;
7878
protected final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
7979
protected final Lock readLock = lock.readLock();
8080
protected final Lock writeLock = lock.writeLock();
8181

82-
RBMIntKeyLookupStore(int modulo, long memSizeCapInBytes) {
83-
this.modulo = modulo;
82+
// Default constructor sets modulo = 2^28
83+
public RBMIntKeyLookupStore(long memSizeCapInBytes) {
84+
this(KeystoreModuloValue.TWO_TO_TWENTY_EIGHT, memSizeCapInBytes);
85+
}
86+
87+
public RBMIntKeyLookupStore(KeystoreModuloValue moduloValue, long memSizeCapInBytes) {
88+
this.modulo = moduloValue.getValue();
8489
sizeEstimator = new RBMSizeEstimator(modulo);
8590
this.stats = new KeyStoreStats(memSizeCapInBytes, calculateMaxNumEntries(memSizeCapInBytes));
8691
this.rbm = new RoaringBitmap();
@@ -94,11 +99,11 @@ protected int calculateMaxNumEntries(long memSizeCapInBytes) {
9499
return sizeEstimator.getNumEntriesFromSizeInBytes(memSizeCapInBytes);
95100
}
96101

97-
protected final int transform(int value) {
102+
private final int transform(int value) {
98103
return modulo == 0 ? value : value % modulo;
99104
}
100105

101-
protected void handleCollisions(int transformedValue) {
106+
private void handleCollisions(int transformedValue) {
102107
stats.numCollisions.inc();
103108
collidedInts.add(transformedValue);
104109
}
@@ -108,18 +113,21 @@ public boolean add(Integer value) throws Exception {
108113
if (value == null) {
109114
return false;
110115
}
111-
writeLock.lock();
112116
stats.numAddAttempts.inc();
117+
if (stats.size.count() == stats.maxNumEntries) {
118+
stats.atCapacity.set(true);
119+
return false;
120+
}
121+
int transformedValue = transform(value);
122+
123+
writeLock.lock();
113124
try {
114-
if (stats.size == stats.maxNumEntries) {
115-
stats.atCapacity = true;
116-
return false;
117-
}
118-
int transformedValue = transform(value);
119-
boolean alreadyContained = contains(value);
125+
boolean alreadyContained;
126+
// saves calling transform() an additional time
127+
alreadyContained = rbm.contains(transformedValue);
120128
if (!alreadyContained) {
121129
rbm.add(transformedValue);
122-
stats.size++;
130+
stats.size.inc();
123131
return true;
124132
}
125133
handleCollisions(transformedValue);
@@ -159,7 +167,7 @@ public boolean remove(Integer value) throws Exception {
159167
int transformedValue = transform(value);
160168
readLock.lock();
161169
try {
162-
if (!contains(value)) {
170+
if (!rbm.contains(transformedValue)) { // saves additional transform() call
163171
return false;
164172
}
165173
stats.numRemovalAttempts.inc();
@@ -172,7 +180,7 @@ public boolean remove(Integer value) throws Exception {
172180
writeLock.lock();
173181
try {
174182
rbm.remove(transformedValue);
175-
stats.size--;
183+
stats.size.dec();
176184
stats.numSuccessfulRemovals.inc();
177185
return true;
178186
} finally {
@@ -184,14 +192,14 @@ public boolean remove(Integer value) throws Exception {
184192
public int getSize() {
185193
readLock.lock();
186194
try {
187-
return stats.size;
195+
return (int) stats.size.count();
188196
} finally {
189197
readLock.unlock();
190198
}
191199
}
192200

193201
@Override
194-
public int getTotalAdds() {
202+
public int getAddAttempts() {
195203
return (int) stats.numAddAttempts.count();
196204
}
197205

@@ -200,7 +208,6 @@ public int getCollisions() {
200208
return (int) stats.numCollisions.count();
201209
}
202210

203-
204211
@Override
205212
public boolean isCollision(Integer value1, Integer value2) {
206213
if (value1 == null || value2 == null) {
@@ -211,7 +218,7 @@ public boolean isCollision(Integer value1, Integer value2) {
211218

212219
@Override
213220
public long getMemorySizeInBytes() {
214-
return sizeEstimator.getSizeInBytes(stats.size) + RBMSizeEstimator.getHashsetMemSizeInBytes(collidedInts.size());
221+
return sizeEstimator.getSizeInBytes((int) stats.size.count()) + RBMSizeEstimator.getHashsetMemSizeInBytes(collidedInts.size());
215222
}
216223

217224
@Override
@@ -221,14 +228,14 @@ public long getMemorySizeCapInBytes() {
221228

222229
@Override
223230
public boolean isFull() {
224-
return stats.atCapacity;
231+
return stats.atCapacity.get();
225232
}
226233

227234
@Override
228235
public void regenerateStore(Integer[] newValues) throws Exception {
229236
rbm.clear();
230237
collidedInts = new HashSet<>();
231-
stats.size = 0;
238+
stats.size = new CounterMetric();
232239
stats.numAddAttempts = new CounterMetric();
233240
stats.numCollisions = new CounterMetric();
234241
stats.guaranteesNoFalseNegatives = true;
@@ -241,12 +248,11 @@ public void regenerateStore(Integer[] newValues) throws Exception {
241248
}
242249
}
243250

244-
245-
246251
@Override
247252
public void clear() throws Exception {
248-
regenerateStore(new Integer[]{});
253+
regenerateStore(new Integer[] {});
249254
}
255+
250256
public int getNumRemovalAttempts() {
251257
return (int) stats.numRemovalAttempts.count();
252258
}

server/src/main/java/org/opensearch/indices/RBMSizeEstimator.java renamed to server/src/main/java/org/opensearch/common/cache/tier/keystore/RBMSizeEstimator.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@
3030
* GitHub history for details.
3131
*/
3232

33-
package org.opensearch.indices;
33+
package org.opensearch.common.cache.tier.keystore;
34+
35+
import org.opensearch.common.cache.tier.keystore.RBMIntKeyLookupStore;
3436

3537
/**
3638
* A class used to estimate roaring bitmap memory sizes (and hash set sizes).
@@ -111,12 +113,16 @@ public static long getSizeInBytesWithModulo(int numEntries, int modulo) {
111113
return (long) ((long) Math.pow(numEntries, memValues[1]) * (long) Math.pow(10, memValues[2]) * memValues[0]);
112114
}
113115

116+
public static long getSizeInBytesWithModuloValue(int numEntries, RBMIntKeyLookupStore.KeystoreModuloValue moduloValue) {
117+
double[] memValues = calculateMemoryCoefficients(moduloValue.getValue());
118+
return (long) ((long) Math.pow(numEntries, memValues[1]) * (long) Math.pow(10, memValues[2]) * memValues[0]);
119+
}
120+
114121
public static int getNumEntriesFromSizeInBytesWithModulo(long sizeInBytes, int modulo) {
115122
double[] memValues = calculateMemoryCoefficients(modulo);
116123
return (int) Math.pow(sizeInBytes / (memValues[0] * Math.pow(10, memValues[2])), 1 / memValues[1]);
117124
}
118125

119-
120126
protected static long convertMBToBytes(double valMB) {
121127
return (long) (valMB * BYTES_IN_MB);
122128
}

0 commit comments

Comments
 (0)