Skip to content

Commit a4fabc0

Browse files
karthikbhat13Google Java Core Libraries
authored andcommitted
Init LockFreeBitArray with length to reduce memory when deserializing BloomFilter.
Second try, setting the `bitCount` property correctly. Closes #5799. Fixes #5770. RELNOTES=n/a PiperOrigin-RevId: 421580967
1 parent c5b0227 commit a4fabc0

File tree

6 files changed

+76
-42
lines changed

6 files changed

+76
-42
lines changed

android/guava-tests/test/com/google/common/hash/BloomFilterTest.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,10 @@ public void testCustomSerialization() throws Exception {
506506
ByteArrayOutputStream out = new ByteArrayOutputStream();
507507
bf.writeTo(out);
508508

509-
assertEquals(bf, BloomFilter.readFrom(new ByteArrayInputStream(out.toByteArray()), funnel));
509+
BloomFilter<byte[]> read =
510+
BloomFilter.readFrom(new ByteArrayInputStream(out.toByteArray()), funnel);
511+
assertThat(read).isEqualTo(bf);
512+
assertThat(read.expectedFpp()).isGreaterThan(0);
510513
}
511514

512515
/**

android/guava/src/com/google/common/hash/BloomFilter.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.google.common.base.Predicate;
2424
import com.google.common.hash.BloomFilterStrategies.LockFreeBitArray;
2525
import com.google.common.math.DoubleMath;
26+
import com.google.common.math.LongMath;
2627
import com.google.common.primitives.SignedBytes;
2728
import com.google.common.primitives.UnsignedBytes;
2829
import com.google.errorprone.annotations.CanIgnoreReturnValue;
@@ -540,11 +541,13 @@ public void writeTo(OutputStream out) throws IOException {
540541
dataLength = din.readInt();
541542

542543
Strategy strategy = BloomFilterStrategies.values()[strategyOrdinal];
543-
long[] data = new long[dataLength];
544-
for (int i = 0; i < data.length; i++) {
545-
data[i] = din.readLong();
544+
545+
LockFreeBitArray dataArray = new LockFreeBitArray(LongMath.checkedMultiply(dataLength, 64L));
546+
for (int i = 0; i < dataLength; i++) {
547+
dataArray.putData(i, din.readLong());
546548
}
547-
return new BloomFilter<T>(new LockFreeBitArray(data), numHashFunctions, funnel, strategy);
549+
550+
return new BloomFilter<T>(dataArray, numHashFunctions, funnel, strategy);
548551
} catch (RuntimeException e) {
549552
String message =
550553
"Unable to deserialize BloomFilter from InputStream."

android/guava/src/com/google/common/hash/BloomFilterStrategies.java

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -263,27 +263,38 @@ void putAll(LockFreeBitArray other) {
263263
data.length(),
264264
other.data.length());
265265
for (int i = 0; i < data.length(); i++) {
266-
long otherLong = other.data.get(i);
267-
268-
long ourLongOld;
269-
long ourLongNew;
270-
boolean changedAnyBits = true;
271-
do {
272-
ourLongOld = data.get(i);
273-
ourLongNew = ourLongOld | otherLong;
274-
if (ourLongOld == ourLongNew) {
275-
changedAnyBits = false;
276-
break;
277-
}
278-
} while (!data.compareAndSet(i, ourLongOld, ourLongNew));
266+
putData(i, other.data.get(i));
267+
}
268+
}
279269

280-
if (changedAnyBits) {
281-
int bitsAdded = Long.bitCount(ourLongNew) - Long.bitCount(ourLongOld);
282-
bitCount.add(bitsAdded);
270+
/**
271+
* ORs the bits encoded in the {@code i}th {@code long} in the underlying {@link
272+
* AtomicLongArray} with the given value.
273+
*/
274+
void putData(int i, long longValue) {
275+
long ourLongOld;
276+
long ourLongNew;
277+
boolean changedAnyBits = true;
278+
do {
279+
ourLongOld = data.get(i);
280+
ourLongNew = ourLongOld | longValue;
281+
if (ourLongOld == ourLongNew) {
282+
changedAnyBits = false;
283+
break;
283284
}
285+
} while (!data.compareAndSet(i, ourLongOld, ourLongNew));
286+
287+
if (changedAnyBits) {
288+
int bitsAdded = Long.bitCount(ourLongNew) - Long.bitCount(ourLongOld);
289+
bitCount.add(bitsAdded);
284290
}
285291
}
286292

293+
/** Returns the number of {@code long}s in the underlying {@link AtomicLongArray}. */
294+
int dataLength() {
295+
return data.length();
296+
}
297+
287298
@Override
288299
public boolean equals(@CheckForNull Object o) {
289300
if (o instanceof LockFreeBitArray) {

guava-tests/test/com/google/common/hash/BloomFilterTest.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,10 @@ public void testCustomSerialization() throws Exception {
522522
ByteArrayOutputStream out = new ByteArrayOutputStream();
523523
bf.writeTo(out);
524524

525-
assertEquals(bf, BloomFilter.readFrom(new ByteArrayInputStream(out.toByteArray()), funnel));
525+
BloomFilter<byte[]> read =
526+
BloomFilter.readFrom(new ByteArrayInputStream(out.toByteArray()), funnel);
527+
assertThat(read).isEqualTo(bf);
528+
assertThat(read.expectedFpp()).isGreaterThan(0);
526529
}
527530

528531
/**

guava/src/com/google/common/hash/BloomFilter.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.google.common.base.Predicate;
2424
import com.google.common.hash.BloomFilterStrategies.LockFreeBitArray;
2525
import com.google.common.math.DoubleMath;
26+
import com.google.common.math.LongMath;
2627
import com.google.common.primitives.SignedBytes;
2728
import com.google.common.primitives.UnsignedBytes;
2829
import com.google.errorprone.annotations.CanIgnoreReturnValue;
@@ -607,11 +608,13 @@ public void writeTo(OutputStream out) throws IOException {
607608
dataLength = din.readInt();
608609

609610
Strategy strategy = BloomFilterStrategies.values()[strategyOrdinal];
610-
long[] data = new long[dataLength];
611-
for (int i = 0; i < data.length; i++) {
612-
data[i] = din.readLong();
611+
612+
LockFreeBitArray dataArray = new LockFreeBitArray(LongMath.checkedMultiply(dataLength, 64L));
613+
for (int i = 0; i < dataLength; i++) {
614+
dataArray.putData(i, din.readLong());
613615
}
614-
return new BloomFilter<T>(new LockFreeBitArray(data), numHashFunctions, funnel, strategy);
616+
617+
return new BloomFilter<T>(dataArray, numHashFunctions, funnel, strategy);
615618
} catch (RuntimeException e) {
616619
String message =
617620
"Unable to deserialize BloomFilter from InputStream."

guava/src/com/google/common/hash/BloomFilterStrategies.java

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -263,27 +263,38 @@ void putAll(LockFreeBitArray other) {
263263
data.length(),
264264
other.data.length());
265265
for (int i = 0; i < data.length(); i++) {
266-
long otherLong = other.data.get(i);
267-
268-
long ourLongOld;
269-
long ourLongNew;
270-
boolean changedAnyBits = true;
271-
do {
272-
ourLongOld = data.get(i);
273-
ourLongNew = ourLongOld | otherLong;
274-
if (ourLongOld == ourLongNew) {
275-
changedAnyBits = false;
276-
break;
277-
}
278-
} while (!data.compareAndSet(i, ourLongOld, ourLongNew));
266+
putData(i, other.data.get(i));
267+
}
268+
}
279269

280-
if (changedAnyBits) {
281-
int bitsAdded = Long.bitCount(ourLongNew) - Long.bitCount(ourLongOld);
282-
bitCount.add(bitsAdded);
270+
/**
271+
* ORs the bits encoded in the {@code i}th {@code long} in the underlying {@link
272+
* AtomicLongArray} with the given value.
273+
*/
274+
void putData(int i, long longValue) {
275+
long ourLongOld;
276+
long ourLongNew;
277+
boolean changedAnyBits = true;
278+
do {
279+
ourLongOld = data.get(i);
280+
ourLongNew = ourLongOld | longValue;
281+
if (ourLongOld == ourLongNew) {
282+
changedAnyBits = false;
283+
break;
283284
}
285+
} while (!data.compareAndSet(i, ourLongOld, ourLongNew));
286+
287+
if (changedAnyBits) {
288+
int bitsAdded = Long.bitCount(ourLongNew) - Long.bitCount(ourLongOld);
289+
bitCount.add(bitsAdded);
284290
}
285291
}
286292

293+
/** Returns the number of {@code long}s in the underlying {@link AtomicLongArray}. */
294+
int dataLength() {
295+
return data.length();
296+
}
297+
287298
@Override
288299
public boolean equals(@CheckForNull Object o) {
289300
if (o instanceof LockFreeBitArray) {

0 commit comments

Comments
 (0)