Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Memory manager prototype #541

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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