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 26, 2021
1 parent f9746ae commit 6d6dd19
Show file tree
Hide file tree
Showing 11 changed files with 906 additions and 116 deletions.
20 changes: 18 additions & 2 deletions RoaringBitmap/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,31 @@ dependencies {
testImplementation("com.fasterxml.jackson.core", "jackson-databind", "2.10.3")
}

val allocationManagerTest = task<Test>("allocationManagerTest") {
// test needs to run in its own fork to ensure registration succeeds
filter {
//include specific method in any of the tests
includeTestsMatching("org.roaringbitmap.AllocationManagerTest")
}
useJUnitPlatform()
failFast = true
}

tasks.test {
dependsOn(allocationManagerTest)
systemProperty("kryo.unsafe", "false")
mustRunAfter(tasks.checkstyleMain)
useJUnitPlatform()
failFast = true
testLogging {
// We exclude 'passed' events
events( "skipped", "failed")
events("skipped", "failed")
showStackTraces = true
exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
}
}
filter {
// must not run this test as registration of the allocation manager will fail,
// but if it succeeded it would cause other tests to fail
excludeTestsMatching("org.roaringbitmap.AllocationManagerTest")
}
}
181 changes: 181 additions & 0 deletions RoaringBitmap/src/main/java/org/roaringbitmap/AllocationManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
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;
}
}

/**
* Register an allocator. Must be registered before first use, otherwise registration will be
* unsuccessful
* @param allocator the allocator
* @return true if registration succeeded
*/
public static boolean register(Allocator allocator) {
return UPDATER.compareAndSet(INSTANCE, null, allocator);
}

/**
* @see Allocator#allocateChars
*/
public static char[] allocateChars(int size) {
return RegisteredAllocator.ALLOCATOR.allocateChars(size);
}

/**
* @see Allocator#allocateLongs
*/
public static long[] allocateLongs(int size) {
return RegisteredAllocator.ALLOCATOR.allocateLongs(size);
}

/**
* @see Allocator#allocateObjects
*/
public static Container[] allocateContainers(int size) {
return RegisteredAllocator.ALLOCATOR.allocateObjects(Container.class, size);
}

/**
* @see Allocator#copy
*/
public static char[] copy(char[] chars) {
return RegisteredAllocator.ALLOCATOR.copy(chars);
}

/**
* @see Allocator#copy
*/
public static char[] copy(char[] chars, int newSize) {
return RegisteredAllocator.ALLOCATOR.copy(chars, newSize);
}

/**
* @see Allocator#copy
*/
public static long[] copy(long[] longs) {
return RegisteredAllocator.ALLOCATOR.copy(longs);
}

/**
* @see Allocator#copy
*/
public static Container[] copy(Container[] containers) {
return RegisteredAllocator.ALLOCATOR.copy(containers);
}

/**
* @see Allocator#copy
*/
public static Container[] copy(Container[] containers, int newSize) {
return RegisteredAllocator.ALLOCATOR.copy(containers, newSize);
}

/**
* @see Allocator#extend
*/
public static char[] extend(char[] chars, int newSize) {
return RegisteredAllocator.ALLOCATOR.extend(chars, newSize);
}

/**
* @see Allocator#extend
*/
public static Container[] extend(Container[] containers, int newSize) {
return RegisteredAllocator.ALLOCATOR.extend(containers, newSize);
}

/**
* @see Allocator#free
*/
public static void free(Object object) {
RegisteredAllocator.ALLOCATOR.free(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 <T> T[] copy(T[] objects, int newSize) {
return Arrays.copyOf(objects, newSize);
}

@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 void free(Object object) {
// do nothing
}
}
}
89 changes: 89 additions & 0 deletions RoaringBitmap/src/main/java/org/roaringbitmap/Allocator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package org.roaringbitmap;

public interface Allocator {

/**
* allocate a new array
* @param size the size of the array
* @return a newly allocated array which should be returned to the pool
*/
char[] allocateChars(int size);

/**
* allocate a new array
* @param size the size of the array
* @return a newly allocated array which should be returned to the pool
*/
long[] allocateLongs(int size);

/**
* Allocate a new array with the element type
* @param clazz the type of the elements
* @param size the size of the array
* @param <T> the type of the elements
* @return a newly allocated array which should be returned to the pool
*/
<T> T[] allocateObjects(Class<T> clazz, int size);

/**
* Copies the array, does not free the input
* @param longs the array to be copied but not freed
* @return a newly allocated array which should be returned to the pool
*/
long[] copy(long[] longs);

/**
* Copies the array, does not free the input
* @param chars the array to be copied but not freed
* @return a newly allocated array which should be returned to the pool
*/
char[] copy(char[] chars);

/**
* Copies the array, does not free the input
* @param chars the array to be copied but not freed
* @param newSize the size of the new array
* @return a newly allocated array which should be returned to the pool
*/
char[] copy(char[] chars, int newSize);

/**
* Copies the array, does not free the input
* @param objects to be copied but not freed
* @param <T> the type of the elements
* @return a newly allocated array which should be returned to the pool
*/
<T> T[] copy(T[] objects);

/**
* Copies the array, does not free the input
* @param objects to be copied but not freed
* @param <T> the type of the elements
* @param newSize the size of the new array
* @return a newly allocated array which should be returned to the pool
*/
<T> T[] copy(T[] objects, int newSize);

/**
* Copy and free the array, return a new array
* @param chars array which will be freed
* @param newSize the size of the new array
* @return a newly allocated array which should be returned to the pool
*/
char[] extend(char[] chars, int newSize);

/**
* Copy and free the array, return a new array
* @param objects objects which will be freed
* @param newSize the size of the newly allocated array
* @param <T> the type
* @return a newly allocated array which should be returned to the pool
*/
<T> T[] extend(T[] objects, int newSize);

/**
* free the object
* @param object the object to free, must not be used afterwards.
*/
void free(Object object);
}
Loading

0 comments on commit 6d6dd19

Please sign in to comment.