Skip to content

Commit

Permalink
Making Int2ObjectMap configurable through a factory.
Browse files Browse the repository at this point in the history
This change allows to register a new Int2ObjectMap factory to the configuration
while keeping the older implementation as the default.
To set up a new factory clients of the library will have to create
a factory and set it through the configuration.
In addition clearing of the default configuration is now responsible for
deciding how to clean itself while maintining implementation details encapsulated.
  • Loading branch information
angularos committed Oct 9, 2017
1 parent 7a47c7d commit 55c1fe0
Show file tree
Hide file tree
Showing 7 changed files with 222 additions and 179 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.nustaq.offheap.structs.structtypes.StructString;
import org.nustaq.serialization.FSTClazzInfo;
import org.nustaq.serialization.FSTConfiguration;
import org.nustaq.serialization.util.DefaultFSTInt2ObjectMap;
import org.nustaq.serialization.util.FSTInt2ObjectMap;
import org.nustaq.serialization.util.FSTUtil;
import javassist.*;
Expand Down Expand Up @@ -596,7 +597,7 @@ protected int computeElemSize(Object container, Object[] objectValue, FSTClazzIn
return align(elemSiz,SIZE_ALIGN);
}

FSTInt2ObjectMap<Class> mIntToClz = new FSTInt2ObjectMap<Class>(97); // id to onheap class
FSTInt2ObjectMap<Class> mIntToClz = conf.getIntToObjectMapFactory().createMap(97); // id to onheap class
HashMap<Class,Integer> mClzToInt = new HashMap<Class,Integer>(); // reverse

int idCount = 1;
Expand Down
15 changes: 14 additions & 1 deletion src/main/java/org/nustaq/serialization/FSTConfiguration.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
import org.nustaq.offheap.bytez.onheap.HeapBytez;
import org.nustaq.offheap.structs.FSTStruct;
import org.nustaq.serialization.coders.*;
import org.nustaq.serialization.util.DefaultFSTInt2ObjectMapFactory;
import org.nustaq.serialization.util.FSTInputStream;
import org.nustaq.serialization.util.FSTInt2ObjectMapFactory;
import org.nustaq.serialization.util.FSTUtil;
import org.nustaq.serialization.serializers.*;
import org.objenesis.Objenesis;
Expand Down Expand Up @@ -94,6 +96,7 @@ public interface ClassSecurityVerifier {
ConfType type = ConfType.DEFAULT;
FSTClazzInfoRegistry serializationInfoRegistry = new FSTClazzInfoRegistry();
HashMap<Class,List<SoftReference>> cachedObjects = new HashMap<Class, List<SoftReference>>(97);
FSTInt2ObjectMapFactory intToObjectMapFactory = new DefaultFSTInt2ObjectMapFactory();
FSTClazzNameRegistry classRegistry = new FSTClazzNameRegistry(null);
boolean preferSpeed = false; // hint to prefer speed over size in case, currently ignored.
boolean shareReferences = true;
Expand All @@ -115,6 +118,10 @@ public FSTConfiguration setVerifier(ClassSecurityVerifier verifier) {
return this;
}

public FSTInt2ObjectMapFactory getIntToObjectMapFactory() {
return intToObjectMapFactory;
}

// cache fieldinfo. This can be shared with derived FSTConfigurations in order to reduce footprint
static class FieldKey {
Class clazz;
Expand Down Expand Up @@ -458,6 +465,7 @@ protected static FSTConfiguration createDefaultConfiguration(ConcurrentHashMap<F
}

protected static FSTConfiguration initDefaultFstConfigurationInternal(FSTConfiguration conf) {
conf.registerIntToObjectMapFactory(new DefaultFSTInt2ObjectMapFactory());
conf.addDefaultClazzes();
// serializers
FSTSerializerRegistry reg = conf.getCLInfoRegistry().getSerializerRegistry();
Expand All @@ -468,7 +476,6 @@ protected static FSTConfiguration initDefaultFstConfigurationInternal(FSTConfigu
reg.putSerializer(Short.class, new FSTBigNumberSerializers.FSTShortSerializer(), false);
reg.putSerializer(Float.class, new FSTBigNumberSerializers.FSTFloatSerializer(), false);
reg.putSerializer(Double.class, new FSTBigNumberSerializers.FSTDoubleSerializer(), false);

reg.putSerializer(Date.class, new FSTDateSerializer(), false);
reg.putSerializer(StringBuffer.class, new FSTStringBufferSerializer(), true);
reg.putSerializer(StringBuilder.class, new FSTStringBuilderSerializer(), true);
Expand All @@ -492,6 +499,12 @@ protected static FSTConfiguration initDefaultFstConfigurationInternal(FSTConfigu
return conf;
}

public void registerIntToObjectMapFactory(FSTInt2ObjectMapFactory intToObjectMapFactory){
if (intToObjectMapFactory != null) {
this.intToObjectMapFactory = intToObjectMapFactory;
}
}

/**
* Returns a configuration using Unsafe to read write data.
* - platform dependent byte order
Expand Down
11 changes: 4 additions & 7 deletions src/main/java/org/nustaq/serialization/FSTObjectRegistry.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,24 +33,21 @@ public final class FSTObjectRegistry {

boolean disabled = false;
FSTIdentity2IdMap objects = new FSTIdentity2IdMap(11); // object => id
FSTInt2ObjectMap idToObject = new FSTInt2ObjectMap(11);
FSTInt2ObjectMap idToObject;

Object reuseMap[] = new Object[POS_MAP_SIZE];
private int highestPos = -1;

public FSTObjectRegistry(FSTConfiguration conf) {

disabled = !conf.isShareReferences();
idToObject = conf.intToObjectMapFactory.createMap(11);
}

public void clearForRead(FSTConfiguration conf) {
disabled = !conf.isShareReferences();
if ( !disabled ) {
if ( idToObject.mKeys.length > 6 * idToObject.size() && idToObject.size() > 0 ) {
// avoid cleaning huge mem areas after having written a large object
idToObject = new FSTInt2ObjectMap(idToObject.size());
} else {
idToObject.clear();
}
idToObject.clear();
if ( highestPos > -1 )
FSTUtil.clear( reuseMap, highestPos + 1 );
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
/*
* Copyright 2014 Ruediger Moeller.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.nustaq.serialization.util;

public class DefaultFSTInt2ObjectMap<V> implements FSTInt2ObjectMap <V>{

private int mKeys[];
private Object mValues[];
private int mNumberOfElements;
private DefaultFSTInt2ObjectMap<V> next;
private static final int GROWFAC = 2;

public DefaultFSTInt2ObjectMap(int initialSize) {
if (initialSize < 2) {
initialSize = 2;
}

initialSize = FSTObject2IntMap.adjustSize(initialSize * 2);

mKeys = new int[initialSize];
mValues = new Object[initialSize];
mNumberOfElements = 0;
}

public int size() {
return mNumberOfElements + (next != null ? next.size() : 0);
}

final public void put(int key, V value) {
int hash = key & 0x7FFFFFFF;
if (key == 0 && value == null) {
throw new RuntimeException("key value pair not supported " + key + " " + value);
}
putHash(key, value, hash, this);
}

final private static <V> void putHash(int key, V value, int hash, DefaultFSTInt2ObjectMap<V> current, DefaultFSTInt2ObjectMap<V> parent) {
int count = 0;
while(true){
if (current.mNumberOfElements * GROWFAC > current.mKeys.length) {
if (parent != null) {
if ((parent.mNumberOfElements + current.mNumberOfElements) * GROWFAC > parent.mKeys.length) {
parent.resize(parent.mKeys.length * GROWFAC);
parent.put(key, value);
return;
} else {
current.resize(current.mKeys.length * GROWFAC);
}
} else {
current.resize(current.mKeys.length * GROWFAC);
}
}

int idx = hash % current.mKeys.length;

if (current.mKeys[idx] == 0 && current.mValues[idx] == null) // new
{
current.mNumberOfElements++;
current.mValues[idx] = value;
current.mKeys[idx] = key;
return;
} else if (current.mKeys[idx] == key) // overwrite
{
current.mValues[idx] = value;
return;
} else {
if (current.next == null) {
// try break edge cases leading to long chains of maps
if ( count > 4 && current.mNumberOfElements < 5 ) {
int newSiz = current.mNumberOfElements*2+1;
current.next = new DefaultFSTInt2ObjectMap<V>(newSiz);
count = 0;
} else {
int newSiz = current.mNumberOfElements / 3;
current.next = new DefaultFSTInt2ObjectMap<V>(newSiz);
}
}
parent = current;
current = current.next;
count ++;
}
}
}

final void putHash(int key, V value, int hash, DefaultFSTInt2ObjectMap<V> parent) {
putHash(key, value, hash,this, parent);
}

final public V get(int key) {
int hash = key & 0x7FFFFFFF;
return getHash(key, hash);
}

final V getHash(int key, int hash) {
final int idx = hash % mKeys.length;

final int mKey = mKeys[idx];
final Object mValue = mValues[idx];
if (mKey == 0 && mValue == null) // not found
{
// hit++;
return null;
} else if (mKey == key) // found
{
// hit++;
return (V) mValue;
} else {
if (next == null) {
return null;
}
// miss++;
return next.getHash(key, hash);
}
}

final void resize(int newSize) {
newSize = FSTObject2IntMap.adjustSize(newSize);
int[] oldTabKey = mKeys;
Object[] oldTabVal = mValues;

mKeys = new int[newSize];
mValues = new Object[newSize];
mNumberOfElements = 0;

for (int n = 0; n < oldTabKey.length; n++) {
if (oldTabKey[n] != 0 || oldTabVal[n] != null) {
put(oldTabKey[n], (V) oldTabVal[n]);
}
}
if (next != null) {
DefaultFSTInt2ObjectMap oldNext = next;
next = null;
oldNext.rePut(this);
}
}

private void rePut(DefaultFSTInt2ObjectMap<V> kfstObject2IntMap) {
for (int i = 0; i < mKeys.length; i++) {
int mKey = mKeys[i];
if (mKey != 0 || mValues[i] != null) {
kfstObject2IntMap.put(mKey, (V) mValues[i]);
}
}
if (next != null) {
next.rePut(kfstObject2IntMap);
}
}

public void clear() {
int size = size();
if (size == 0)
return;
if (mKeys.length > 6 * size() && size > 0) {
// avoid cleaning huge mem areas after having written a large object
if (size < 2) {
size = 2;
}
size = FSTObject2IntMap.adjustSize(size * 2);
mKeys = new int[size];
mValues = new Object[size];
mNumberOfElements = 0;
} else {
FSTUtil.clear(mKeys);
FSTUtil.clear(mValues);
mNumberOfElements = 0;
if (next != null) {
next.clear();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.nustaq.serialization.util;

public class DefaultFSTInt2ObjectMapFactory implements FSTInt2ObjectMapFactory{
@Override
public <V> FSTInt2ObjectMap<V> createMap(int size) {
return new DefaultFSTInt2ObjectMap<>(size);
}
}
Loading

0 comments on commit 55c1fe0

Please sign in to comment.