Skip to content

Commit

Permalink
add ConcurrentOnHeapHnswGraph and Builder
Browse files Browse the repository at this point in the history
Tests run against the new Concurrent classes, except where that doesn't make sense
  • Loading branch information
jbellis committed Apr 28, 2023
1 parent e413919 commit c047b06
Show file tree
Hide file tree
Showing 10 changed files with 1,085 additions and 60 deletions.
165 changes: 165 additions & 0 deletions lucene/core/src/java/org/apache/lucene/util/AtomicBitSet.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package org.apache.lucene.util;

import java.util.concurrent.atomic.AtomicLongArray;
import org.apache.lucene.search.DocIdSetIterator;

/**
* A {@link BitSet} implementation that offers concurrent, lock-free access through an {@link
* AtomicLongArray} as bit storage.
*/
public class AtomicBitSet extends BitSet {
private static final long BASE_RAM_BYTES_USED =
RamUsageEstimator.shallowSizeOfInstance(AtomicBitSet.class);

private AtomicLongArray storage;
private int numBits;

public AtomicBitSet(int numBits) {
this.numBits = numBits;
int numLongs = (numBits + 63) >>> 6;
storage = new AtomicLongArray(numLongs);
}

private static int index(int bit) {
return bit >>> 6;
}

private static long mask(int bit) {
return 1L << (bit & 63);
}

@Override
public int length() {
return numBits;
}

private void expandStorage(int minCapacity) {
int numLongs = (minCapacity + 63) >>> 6;
AtomicLongArray newStorage = new AtomicLongArray(numLongs);
for (int i = 0; i < storage.length(); i++) {
newStorage.set(i, storage.get(i));
}
storage = newStorage;
numBits = numLongs << 6;
}

@Override
public void set(int i) {
if (i >= numBits) {
expandStorage(i + 1);
}
int idx = index(i);
long mask = mask(i);
long prev, next;
do {
prev = storage.get(idx);
next = prev | mask;
} while (!storage.compareAndSet(idx, prev, next));
}

@Override
public boolean get(int i) {
if (i >= numBits) {
return false;
}
int idx = index(i);
long mask = mask(i);
long value = storage.get(idx);
return (value & mask) != 0;
}

@Override
public boolean getAndSet(int i) {
if (i >= numBits) {
expandStorage(i + 1);
}
int idx = index(i);
long mask = mask(i);
long prev, next;
do {
prev = storage.get(idx);
next = prev | mask;
} while (!storage.compareAndSet(idx, prev, next));
return (prev & mask) != 0;
}

@Override
public void clear(int i) {
if (i >= numBits) {
return;
}
int idx = index(i);
long mask = mask(i);
long prev, next;
do {
prev = storage.get(idx);
next = prev & ~mask;
} while (!storage.compareAndSet(idx, prev, next));
}

@Override
public void clear(int startIndex, int endIndex) {
int startIdx = index(startIndex);
int endIdx = index(endIndex - 1);
for (int i = startIdx; i <= endIdx; i++) {
long prev, next;
do {
prev = storage.get(i);
next = (i == startIdx) ? prev & ~(-1L << (startIndex & 63)) : prev;
next = (i == endIdx) ? next & (-1L << (endIndex & 63)) : next;
} while (!storage.compareAndSet(i, prev, next));
}
}

@Override
public int cardinality() {
int count = 0;
for (int i = 0; i < storage.length(); i++) {
count += Long.bitCount(storage.get(i));
}
return count;
}

@Override
public int approximateCardinality() {
return cardinality();
}

@Override
public int prevSetBit(int index) {
int idx = index(index);
long mask = (1L << (index & 63)) - 1;

for (int i = idx; i >= 0; i--) {
long word = storage.get(i) & mask;
if (word != 0) {
return (i << 6) + Long.numberOfTrailingZeros(Long.lowestOneBit(word));
}
mask = -1L;
}
return -1;
}

@Override
public int nextSetBit(int index) {
int idx = index(index);
long mask = -1L >>> (63 - (index & 63));

for (int i = idx; i < storage.length(); i++) {
long word = storage.get(i) & mask;
if (word != 0) {
return (i << 6) + Long.numberOfTrailingZeros(Long.lowestOneBit(word));
}
mask = -1L;
}
return DocIdSetIterator.NO_MORE_DOCS;
}

@Override
public long ramBytesUsed() {
final int longSizeInBytes = Long.BYTES;
final int arrayOverhead = 16; // Estimated overhead of AtomicLongArray object in bytes
long storageSize = (long) storage.length() * longSizeInBytes + arrayOverhead;
return BASE_RAM_BYTES_USED + storageSize;
}
}
Loading

0 comments on commit c047b06

Please sign in to comment.