Skip to content

Commit

Permalink
implement a maybe workable memory manager
Browse files Browse the repository at this point in the history
  • Loading branch information
richardstartin committed Nov 25, 2021
1 parent f9746ae commit 26aa44c
Show file tree
Hide file tree
Showing 10 changed files with 466 additions and 74 deletions.
132 changes: 132 additions & 0 deletions RoaringBitmap/src/main/java/org/roaringbitmap/AllocationManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package org.roaringbitmap;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

/**
* Provides A lazily initialised constant allocator. To override allocation,
* registration must take place before first use.
*/
public final class AllocationManager {

private static final AllocationManager INSTANCE = new AllocationManager();

private static final AtomicReferenceFieldUpdater<AllocationManager, Allocator> UPDATER =
AtomicReferenceFieldUpdater.newUpdater(AllocationManager.class, Allocator.class, "providedAllocator");

private volatile Allocator providedAllocator;

private static final class RegisteredAllocator {
public static final Allocator ALLOCATOR;
static {
Allocator allocator = INSTANCE.providedAllocator;
if (allocator == null) {
allocator = new DefaultAllocator();
if (!UPDATER.compareAndSet(INSTANCE, null, allocator)) {
allocator = INSTANCE.providedAllocator;
}
}
ALLOCATOR = allocator;
}
}

public static boolean register(Allocator allocator) {
return UPDATER.compareAndSet(INSTANCE, null, allocator);
}

public static char[] allocateChars(int size) {
return RegisteredAllocator.ALLOCATOR.allocateChars(size);
}

public static long[] allocateLongs(int size) {
return RegisteredAllocator.ALLOCATOR.allocateLongs(size);
}

public static Container[] allocateContainers(int size) {
return RegisteredAllocator.ALLOCATOR.allocateObjects(Container.class, size);
}

public static char[] copy(char[] chars) {
return RegisteredAllocator.ALLOCATOR.copy(chars);
}

public static char[] copy(char[] chars, int newSize) {
return RegisteredAllocator.ALLOCATOR.copy(chars, newSize);
}

public static long[] copy(long[] longs) {
return RegisteredAllocator.ALLOCATOR.copy(longs);
}

public static Container[] copy(Container[] containers) {
return RegisteredAllocator.ALLOCATOR.copy(containers);
}

public static char[] extend(char[] chars, int newSize) {
return RegisteredAllocator.ALLOCATOR.extend(chars, newSize);
}

public static Container[] extend(Container[] containers, int newSize) {
return RegisteredAllocator.ALLOCATOR.extend(containers, newSize);
}

public static <T> void free(Class<T> clazz, Object object) {
RegisteredAllocator.ALLOCATOR.free(clazz, object);
}

static final class DefaultAllocator implements Allocator {

@Override
public char[] allocateChars(int size) {
return new char[size];
}

@Override
public long[] allocateLongs(int size) {
return new long[size];
}

@Override
@SuppressWarnings("unchecked")
public <T> T[] allocateObjects(Class<T> clazz, int size) {
return (T[]) Array.newInstance(clazz, size);
}

@Override
public long[] copy(long[] longs) {
return Arrays.copyOf(longs, longs.length);
}

@Override
public char[] copy(char[] chars) {
return Arrays.copyOf(chars, chars.length);
}

@Override
public char[] copy(char[] chars, int newSize) {
return Arrays.copyOf(chars, newSize);
}

@Override
public <T> T[] copy(T[] objects) {
return Arrays.copyOf(objects, objects.length);
}

@Override
public char[] extend(char[] chars, int newSize) {
return Arrays.copyOf(chars, newSize);
}

@Override
@SuppressWarnings("unchecked")
public <T> T[] extend(T[] objects, int newSize) {
return Arrays.copyOf(objects, newSize);
}

@Override
public <T> void free(Class<T> clazz, Object object) {
// do nothing
}
}
}
82 changes: 82 additions & 0 deletions RoaringBitmap/src/main/java/org/roaringbitmap/Allocator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package org.roaringbitmap;

public interface Allocator {

/**
* allocate a new array
* @param size
* @return
*/
char[] allocateChars(int size);

/**
* allocate a new array
* @param size
* @return
*/
long[] allocateLongs(int size);

/**
* Allocate a new array with the element type
* @param clazz
* @param size
* @param <T>
* @return
*/
<T> T[] allocateObjects(Class<T> clazz, int size);

/**
* Copies the array, does not free the input
* @param longs
* @return
*/
long[] copy(long[] longs);

/**
* Copies the array, does not free the input
* @param chars
* @return
*/
char[] copy(char[] chars);

/**
* Copies the array, does not free the input
* @param chars
* @param newSize
* @return
*/
char[] copy(char[] chars, int newSize);

/**
* Copies the array, does not free the input
* @param objects
* @param <T>
* @return
*/
<T> T[] copy(T[] objects);

/**
* Copy and free the array, return a new array
* @param chars
* @param newSize
* @return
*/
char[] extend(char[] chars, int newSize);

/**
* Copy and free the array, return a new array
* @param objects
* @param newSize
* @param <T>
* @return
*/
<T> T[] extend(T[] objects, int newSize);

/**
* free the object
* @param clazz
* @param object
* @param <T>
*/
<T> void free(Class<T> clazz, Object object);
}
27 changes: 17 additions & 10 deletions RoaringBitmap/src/main/java/org/roaringbitmap/ArrayContainer.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import java.util.Arrays;
import java.util.Iterator;


import static org.roaringbitmap.AllocationManager.*;


/**
Expand Down Expand Up @@ -54,7 +54,7 @@ public static ArrayContainer empty() {
* @param capacity The capacity of the container
*/
public ArrayContainer(final int capacity) {
content = new char[capacity];
content = allocateChars(capacity);
}

/**
Expand All @@ -66,7 +66,7 @@ public ArrayContainer(final int capacity) {
*/
public ArrayContainer(final int firstOfRun, final int lastOfRun) {
final int valuesInRange = lastOfRun - firstOfRun;
this.content = new char[valuesInRange];
this.content = allocateChars(valuesInRange);
for (int i = 0; i < valuesInRange; ++i) {
content[i] = (char) (firstOfRun + i);
}
Expand All @@ -81,7 +81,7 @@ public ArrayContainer(final int firstOfRun, final int lastOfRun) {
*/
public ArrayContainer(int newCard, char[] newContent) {
this.cardinality = newCard;
this.content = Arrays.copyOf(newContent, newCard);
this.content = extend(newContent, newCard);
}

/**
Expand Down Expand Up @@ -352,7 +352,7 @@ protected boolean contains(BitmapContainer bitmapContainer) {
public void deserialize(DataInput in) throws IOException {
this.cardinality = 0xFFFF & Character.reverseBytes(in.readChar());
if (this.content.length < this.cardinality) {
this.content = new char[this.cardinality];
this.content = extend(this.content, this.cardinality);
}
for (int k = 0; k < this.cardinality; ++k) {
this.content[k] = Character.reverseBytes(in.readChar());
Expand Down Expand Up @@ -508,7 +508,7 @@ public Container iadd(int begin, int end) {
* is cardinality and equation holds true , hence "<" equation holds true always
*/
if (newcardinality >= this.content.length) {
char[] destination = new char[calculateCapacity(newcardinality)];
char[] destination = allocateChars(calculateCapacity(newcardinality));
// if b > 0, we copy from 0 to b. Do nothing otherwise.
System.arraycopy(content, 0, destination, 0, indexstart);
// set values from b to e
Expand All @@ -521,6 +521,7 @@ public Container iadd(int begin, int end) {
*/
System.arraycopy(content, indexend, destination, indexstart + rangelength, cardinality
- indexend);
free(char[].class, content);
this.content = destination;
} else {
System
Expand Down Expand Up @@ -608,7 +609,7 @@ private void increaseCapacity(boolean allowIllegalSize) {
&& !allowIllegalSize) {
newCapacity = ArrayContainer.DEFAULT_MAX_SIZE;
}
this.content = Arrays.copyOf(this.content, newCapacity);
this.content = extend(this.content, newCapacity);
}

private int calculateCapacity(int min) {
Expand Down Expand Up @@ -656,7 +657,7 @@ public Container inot(final int firstOfRange, final int lastOfRange) {
if (newCardinality > DEFAULT_MAX_SIZE) {
return toBitmapContainer().inot(firstOfRange, lastOfRange);
}
content = Arrays.copyOf(content, newCardinality);
content = extend(content, newCardinality);
}
// slide right the contents after the range
System.arraycopy(content, lastIndex + 1, content, lastIndex + 1 + cardinalityChange,
Expand Down Expand Up @@ -732,10 +733,11 @@ public Container ior(final ArrayContainer value2) {
}
if (totalCardinality >= content.length) {
int newCapacity = calculateCapacity(totalCardinality);
char[] destination = new char[newCapacity];
char[] destination = allocateChars(newCapacity);
cardinality =
Util.unsignedUnion2by2(content, 0, cardinality, value2.content, 0, value2.cardinality,
destination);
free(char[].class, content);
this.content = destination;
} else {
System.arraycopy(content, 0, content, value2.cardinality, cardinality);
Expand Down Expand Up @@ -1256,6 +1258,11 @@ public int last() {
return (content[cardinality - 1]);
}

@Override
public void close() {
free(char[].class, content);
}

@Override
public MappeableContainer toMappeableContainer() {
return new MappeableArrayContainer(this);
Expand Down Expand Up @@ -1294,7 +1301,7 @@ public void trim() {
if (this.content.length == this.cardinality) {
return;
}
this.content = Arrays.copyOf(this.content, this.cardinality);
this.content = extend(this.content, this.cardinality);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@

import static java.lang.Long.bitCount;
import static java.lang.Long.numberOfTrailingZeros;
import static org.roaringbitmap.AllocationManager.*;


/**
* Simple bitset-like container.
*/
public final class BitmapContainer extends Container implements Cloneable {
public final class BitmapContainer extends Container implements Cloneable, AutoCloseable {
public static final int MAX_CAPACITY = 1 << 16;


Expand Down Expand Up @@ -77,7 +78,7 @@ protected static int serializedSizeInBytes(int unusedCardinality) {
*/
public BitmapContainer() {
this.cardinality = 0;
this.bitmap = new long[MAX_CAPACITY / 64];
this.bitmap = allocateLongs(MAX_CAPACITY / 64);
}


Expand All @@ -91,13 +92,13 @@ public BitmapContainer() {
*/
public BitmapContainer(final int firstOfRun, final int lastOfRun) {
this.cardinality = lastOfRun - firstOfRun;
this.bitmap = new long[MAX_CAPACITY / 64];
this.bitmap = allocateLongs(MAX_CAPACITY / 64);
Util.setBitmapRange(bitmap, firstOfRun, lastOfRun);
}

private BitmapContainer(int newCardinality, long[] newBitmap) {
this.cardinality = newCardinality;
this.bitmap = Arrays.copyOf(newBitmap, newBitmap.length);
this.bitmap = copy(newBitmap);
}

/**
Expand Down Expand Up @@ -1700,6 +1701,10 @@ public int last() {
return (i + 1) * 64 - Long.numberOfLeadingZeros(bitmap[i]) - 1;
}

@Override
public void close() {
free(long[].class, bitmap);
}
}


Expand Down
5 changes: 4 additions & 1 deletion RoaringBitmap/src/main/java/org/roaringbitmap/Container.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* Base container class.
*/
public abstract class Container implements Iterable<Character>, Cloneable, Externalizable,
WordStorage<Container> {
WordStorage<Container>, AutoCloseable {

/**
* Create a container initialized with a range of consecutive values
Expand Down Expand Up @@ -1032,4 +1032,7 @@ protected void assertNonEmpty(boolean condition) {
throw new NoSuchElementException("Empty " + getContainerName());
}
}

@Override
public abstract void close();
}
Loading

0 comments on commit 26aa44c

Please sign in to comment.