Created
November 19, 2015 15:17
-
-
Save manuelleduc/c7384d4a754695a02213 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
namespace test { | |
public class DistortedTimeResolver: KResolver { | |
private static int KEYS_SIZE = 3; | |
private KChunkSpaceManager _spaceManager; | |
private KInternalDataManager _manager; | |
public DistortedTimeResolver(KChunkSpaceManager p_cache, KInternalDataManager p_manager) { | |
this._spaceManager = p_cache; | |
this._manager = p_manager; | |
this._spaceManager.setResolver(this); | |
} | |
public KTask lookup(long universe, long time, long uuid, KCallback < KObject > callback) { | |
DistortedTimeResolver selfPointer = this; | |
return () => { | |
try { | |
selfPointer.getOrLoadAndMark(KConfig.NULL_LONG, KConfig.NULL_LONG, KConfig.NULL_LONG, (KChunk theGlobalUniverseOrderElement) => { | |
if (theGlobalUniverseOrderElement != null) { | |
selfPointer.getOrLoadAndMark(KConfig.NULL_LONG, KConfig.NULL_LONG, uuid, (KChunk theObjectUniverseOrderElement) => { | |
if (theObjectUniverseOrderElement == null) { | |
selfPointer._spaceManager.unmarkMemoryElement(theGlobalUniverseOrderElement); | |
callback(null); | |
} else { | |
long closestUniverse = resolve_universe((KLongLongMap) theGlobalUniverseOrderElement, (KLongLongMap) theObjectUniverseOrderElement, time, universe); | |
selfPointer.getOrLoadAndMark(closestUniverse, KConfig.NULL_LONG, uuid, (KChunk theObjectTimeTreeElement) => { | |
if (theObjectTimeTreeElement == null) { | |
selfPointer._spaceManager.unmarkMemoryElement(theObjectUniverseOrderElement); | |
selfPointer._spaceManager.unmarkMemoryElement(theGlobalUniverseOrderElement); | |
callback(null); | |
} else { | |
long closestTime = ((KLongTree) theObjectTimeTreeElement).previousOrEqual(time); | |
if (closestTime == KConfig.NULL_LONG) { | |
selfPointer._spaceManager.unmarkMemoryElement(theObjectTimeTreeElement); | |
selfPointer._spaceManager.unmarkMemoryElement(theObjectUniverseOrderElement); | |
selfPointer._spaceManager.unmarkMemoryElement(theGlobalUniverseOrderElement); | |
callback(null); | |
return; | |
} | |
selfPointer.getOrLoadAndMark(closestUniverse, closestTime, uuid, (KChunk theObjectChunk) => { | |
if (theObjectChunk == null) { | |
selfPointer._spaceManager.unmarkMemoryElement(theObjectTimeTreeElement); | |
selfPointer._spaceManager.unmarkMemoryElement(theObjectUniverseOrderElement); | |
selfPointer._spaceManager.unmarkMemoryElement(theGlobalUniverseOrderElement); | |
callback(null); | |
} else { | |
KMetaClass resolvedMetaClass = selfPointer._manager.model().metaModel().metaClass(((KObjectChunk) theObjectChunk).metaClassIndex()); | |
KObject newProxy = ((AbstractKModel) selfPointer._manager.model()).createProxy(universe, time, uuid, resolvedMetaClass, closestUniverse, closestTime); | |
selfPointer._spaceManager.register(newProxy); | |
callback(newProxy); | |
} | |
}); | |
} | |
}); | |
} | |
}); | |
} | |
}); | |
} catch (Exception e) { | |
//e.printStackTrace(); | |
} | |
}; | |
} | |
public KTask lookupAllObjects(long universe, long time, long[] uuids, KCallback < KObject[] > callback) { | |
DistortedTimeResolver selfPointer = this; | |
return () => { | |
try { | |
selfPointer.getOrLoadAndMark(KConfig.NULL_LONG, KConfig.NULL_LONG, KConfig.NULL_LONG, (KChunk theGlobalUniverseOrderElement) => { | |
if (theGlobalUniverseOrderElement != null) { | |
long[] tempObjectUniverseKeys = new long[uuids.Length * 3]; | |
for (int i = 0; i < uuids.Length; i++) { | |
tempObjectUniverseKeys[i * 3] = KConfig.NULL_LONG; | |
tempObjectUniverseKeys[i * 3 + 1] = KConfig.NULL_LONG; | |
tempObjectUniverseKeys[i * 3 + 2] = uuids[i]; | |
} | |
selfPointer.getOrLoadAndMarkAll(tempObjectUniverseKeys, (KChunk[] objectUniverseOrderElements) => { | |
if (objectUniverseOrderElements == null || objectUniverseOrderElements.Length == 0) { | |
selfPointer._spaceManager.unmarkMemoryElement(theGlobalUniverseOrderElement); | |
callback(new KObject[0]); | |
return; | |
} | |
long[] tempObjectTimeTreeKeys = new long[uuids.Length * 3]; | |
for (int i = 0; i < uuids.Length; i++) { | |
long closestUniverse = resolve_universe((KLongLongMap) theGlobalUniverseOrderElement, (KLongLongMap) objectUniverseOrderElements[i], time, universe); | |
tempObjectTimeTreeKeys[i * 3] = closestUniverse; | |
tempObjectTimeTreeKeys[i * 3 + 1] = KConfig.NULL_LONG; | |
tempObjectTimeTreeKeys[i * 3 + 2] = uuids[i]; | |
} | |
selfPointer.getOrLoadAndMarkAll(tempObjectTimeTreeKeys, (KChunk[] objectTimeTreeElements) => { | |
if (objectTimeTreeElements == null || objectTimeTreeElements.Length == 0) { | |
selfPointer._spaceManager.unmarkAllMemoryElements(objectUniverseOrderElements); | |
selfPointer._spaceManager.unmarkMemoryElement(theGlobalUniverseOrderElement); | |
callback(new KObject[0]); | |
return; | |
} | |
long[] tempObjectChunkKeys = new long[uuids.Length * 3]; | |
for (int i = 0; i < uuids.Length; i++) { | |
long closestTime = ((KLongTree) objectTimeTreeElements[i]).previousOrEqual(time); | |
if (closestTime != KConfig.NULL_LONG) { | |
tempObjectChunkKeys[i * 3] = tempObjectTimeTreeKeys[i * 3]; | |
tempObjectChunkKeys[i * 3 + 1] = closestTime; | |
tempObjectChunkKeys[i * 3 + 2] = uuids[i]; | |
} else { | |
// TODO System.arraycopy(KContentKey.NULL_KEY, 0, tempObjectChunkKeys, (i * 3), 3); | |
} | |
} | |
selfPointer.getOrLoadAndMarkAll(tempObjectChunkKeys, (KChunk[] theObjectChunks) => { | |
if (theObjectChunks == null /*|| System.arraycopy == 0*/ ) { | |
selfPointer._spaceManager.unmarkAllMemoryElements(objectTimeTreeElements); | |
selfPointer._spaceManager.unmarkAllMemoryElements(objectUniverseOrderElements); | |
selfPointer._spaceManager.unmarkMemoryElement(theGlobalUniverseOrderElement); | |
callback(new KObject[0]); | |
} else { | |
KObject[] finalResult = new KObject[uuids.Length]; | |
for (int h = 0; h < theObjectChunks.Length; h++) { | |
if (theObjectChunks[h] != null) { | |
finalResult[h] = ((AbstractKModel) selfPointer._manager.model()).createProxy(universe, time, uuids[h], selfPointer._manager.model().metaModel().metaClass(((KObjectChunk) theObjectChunks[h]).metaClassIndex()), tempObjectTimeTreeKeys[h * 3], tempObjectChunkKeys[h * 3 + 1]); | |
} else { | |
finalResult[h] = null; | |
} | |
} | |
selfPointer._spaceManager.registerAll(finalResult); | |
callback(finalResult); | |
} | |
}); | |
}); | |
}); | |
} | |
}); | |
} catch (Exception e) { | |
//e.printStackTrace(); | |
} | |
}; | |
} | |
public KTask lookupPreciseKeys(long[] keys, KCallback < KObject[] > callback) { | |
DistortedTimeResolver selfPointer = this; | |
return () => { | |
try { | |
selfPointer.getOrLoadAndMark(KConfig.NULL_LONG, KConfig.NULL_LONG, KConfig.NULL_LONG, (theGlobalUniverseOrderElement) => { | |
if (theGlobalUniverseOrderElement != null) { | |
long[] allOrderedKeys = new long[keys.Length * 3]; | |
int insertIndex = 0; | |
int nbKeys = keys.Length / 3; | |
for (int i = 0; i < nbKeys; i++) { | |
//objectUniverseOrder | |
allOrderedKeys[insertIndex] = KConfig.NULL_LONG; | |
insertIndex++; | |
allOrderedKeys[insertIndex] = KConfig.NULL_LONG; | |
insertIndex++; | |
allOrderedKeys[insertIndex] = keys[i * 3 + 2]; | |
insertIndex++; | |
//objectTimeORder | |
allOrderedKeys[insertIndex] = keys[i * 3]; | |
insertIndex++; | |
allOrderedKeys[insertIndex] = KConfig.NULL_LONG; | |
insertIndex++; | |
allOrderedKeys[insertIndex] = keys[i * 3 + 2]; | |
insertIndex++; | |
//objectChunk | |
allOrderedKeys[insertIndex] = keys[i * 3]; | |
insertIndex++; | |
allOrderedKeys[insertIndex] = keys[i * 3 + 1]; | |
insertIndex++; | |
allOrderedKeys[insertIndex] = keys[i * 3 + 2]; | |
insertIndex++; | |
} | |
selfPointer.getOrLoadAndMarkAll(allOrderedKeys, (kChunks) => { | |
if (kChunks == null || kChunks.Length == 0) { | |
selfPointer._spaceManager.unmarkMemoryElement(theGlobalUniverseOrderElement); | |
callback(new KObject[0]); | |
} else { | |
KObject[] finalResult = new KObject[nbKeys]; | |
int insertIndex1 = 0; | |
int previousClassIndex = -1; | |
foreach(KChunk kChunk in kChunks) { | |
if (kChunk != null && kChunk.type() == KChunkTypes.OBJECT_CHUNK) { | |
finalResult[insertIndex1] = ((AbstractKModel) selfPointer._manager.model()).createProxy(kChunk.universe(), kChunk.time(), kChunk.obj(), selfPointer._manager.model().metaModel().metaClass(previousClassIndex), kChunk.universe(), kChunk.time()); | |
insertIndex1++; | |
} else if (kChunk != null && kChunk.type() == KChunkTypes.LONG_LONG_MAP) { | |
KLongLongMap casted = (KLongLongMap) kChunk; | |
previousClassIndex = casted.metaClassIndex(); | |
} | |
} | |
selfPointer._spaceManager.registerAll(finalResult); | |
callback(finalResult); | |
} | |
}); | |
} | |
}); | |
} catch (Exception e) { | |
//e.printStackTrace(); | |
} | |
}; | |
} | |
public KTask lookupPrepared(KPreparedLookup preparedLookup, KCallback < KObject[] > callback) { | |
DistortedTimeResolver selfPointer = this; | |
int nbObjs = preparedLookup.flatLookup().Length / 3; | |
long[] flat = preparedLookup.flatLookup(); | |
return () => { | |
try { | |
selfPointer.getOrLoadAndMark(KConfig.NULL_LONG, KConfig.NULL_LONG, KConfig.NULL_LONG, (theGlobalUniverseOrderElement) => { | |
if (theGlobalUniverseOrderElement != null) { | |
long[] tempObjectUniverseKeys = new long[nbObjs * 3]; | |
for (int i = 0; i < nbObjs; i++) { | |
tempObjectUniverseKeys[i * 3] = KConfig.NULL_LONG; | |
tempObjectUniverseKeys[i * 3 + 1] = KConfig.NULL_LONG; | |
tempObjectUniverseKeys[i * 3 + 2] = flat[i * 3 + 2]; | |
} | |
selfPointer.getOrLoadAndMarkAll(tempObjectUniverseKeys, (objectUniverseOrderElements) => { | |
if (objectUniverseOrderElements == null || objectUniverseOrderElements.Length == 0) { | |
selfPointer._spaceManager.unmarkMemoryElement(theGlobalUniverseOrderElement); | |
callback(new KObject[0]); | |
return; | |
} | |
long[] tempObjectTimeTreeKeys = new long[nbObjs * 3]; | |
for (int i = 0; i < nbObjs; i++) { | |
long closestUniverse = resolve_universe((KLongLongMap) theGlobalUniverseOrderElement, (KLongLongMap) objectUniverseOrderElements[i], flat[i * 3 + 1], flat[i * 3]); | |
tempObjectTimeTreeKeys[i * 3] = closestUniverse; | |
tempObjectTimeTreeKeys[i * 3 + 1] = KConfig.NULL_LONG; | |
tempObjectTimeTreeKeys[i * 3 + 2] = flat[i * 3 + 2]; | |
} | |
selfPointer.getOrLoadAndMarkAll(tempObjectTimeTreeKeys, (objectTimeTreeElements) => { | |
if (objectTimeTreeElements == null || objectTimeTreeElements.Length == 0) { | |
selfPointer._spaceManager.unmarkAllMemoryElements(objectUniverseOrderElements); | |
selfPointer._spaceManager.unmarkMemoryElement(theGlobalUniverseOrderElement); | |
callback(new KObject[0]); | |
return; | |
} | |
long[] tempObjectChunkKeys = new long[nbObjs * 3]; | |
for (int i = 0; i < nbObjs; i++) { | |
long closestTime = ((KLongTree) objectTimeTreeElements[i]).previousOrEqual(flat[i * 3 + 1]); | |
if (closestTime != KConfig.NULL_LONG) { | |
tempObjectChunkKeys[i * 3] = tempObjectTimeTreeKeys[i * 3]; | |
tempObjectChunkKeys[i * 3 + 1] = closestTime; | |
tempObjectChunkKeys[i * 3 + 2] = flat[i * 3 + 2]; | |
} else { | |
// TODO System.arraycopy(KContentKey.NULL_KEY, 0, tempObjectChunkKeys, (i * 3), 3); | |
} | |
} | |
selfPointer.getOrLoadAndMarkAll(tempObjectChunkKeys, (theObjectChunks) => { | |
if (theObjectChunks == null || theObjectChunks.Length == 0) { | |
selfPointer._spaceManager.unmarkAllMemoryElements(objectTimeTreeElements); | |
selfPointer._spaceManager.unmarkAllMemoryElements(objectUniverseOrderElements); | |
selfPointer._spaceManager.unmarkMemoryElement(theGlobalUniverseOrderElement); | |
callback(new KObject[0]); | |
} else { | |
KObject[] finalResult = new KObject[nbObjs]; | |
for (int h = 0; h < theObjectChunks.Length; h++) { | |
if (theObjectChunks[h] != null) { | |
finalResult[h] = ((AbstractKModel) selfPointer._manager.model()).createProxy(flat[h * 3], flat[h * 3 + 1], flat[h * 3 + 2], selfPointer._manager.model().metaModel().metaClass(((KObjectChunk) theObjectChunks[h]).metaClassIndex()), tempObjectTimeTreeKeys[h * 3], tempObjectChunkKeys[h * 3 + 1]); | |
} else { | |
finalResult[h] = null; | |
} | |
} | |
selfPointer._spaceManager.registerAll(finalResult); | |
callback(finalResult); | |
} | |
}); | |
}); | |
}); | |
} | |
}); | |
} catch (Exception e) { | |
//e.printStackTrace(); | |
} | |
}; | |
} | |
public KTask lookupAllTimes(long universe, long[] times, long uuid, KCallback < KObject[] > callback) { | |
DistortedTimeResolver selfPointer = this; | |
return () => { | |
try { | |
selfPointer.getOrLoadAndMark(KConfig.NULL_LONG, KConfig.NULL_LONG, KConfig.NULL_LONG, (theGlobalUniverseOrderElement) => { | |
if (theGlobalUniverseOrderElement != null) { | |
selfPointer.getOrLoadAndMark(KConfig.NULL_LONG, KConfig.NULL_LONG, uuid, (theObjectUniverseOrderElement) => { | |
if (theObjectUniverseOrderElement == null) { | |
selfPointer._spaceManager.unmarkMemoryElement(theGlobalUniverseOrderElement); | |
callback(null); | |
} else { | |
long[] closestUniverses = new long[times.Length]; | |
ArrayLongLongMap closestUnikUniverse = new ArrayLongLongMap(-1, -1, -1, null); | |
int nbUniverseToload = 0; | |
for (int i = 0; i < times.Length; i++) { | |
closestUniverses[i] = resolve_universe((KLongLongMap) theGlobalUniverseOrderElement, (KLongLongMap) theObjectUniverseOrderElement, times[i], universe); | |
if (!closestUnikUniverse.contains(closestUniverses[i])) { | |
closestUnikUniverse.put(closestUniverses[i], nbUniverseToload); | |
nbUniverseToload++; | |
} | |
} | |
long[] toLoadUniverseKeys = new long[nbUniverseToload * 3]; | |
foreach(var entry in closestUnikUniverse) { | |
var key = entry.Key; | |
var value = entry.Value; | |
int currentIndex = (int)(value * 3); | |
toLoadUniverseKeys[currentIndex] = value; | |
toLoadUniverseKeys[currentIndex + 1] = KConfig.NULL_LONG; | |
toLoadUniverseKeys[currentIndex + 2] = uuid; | |
} | |
selfPointer.getOrLoadAndMarkAll(toLoadUniverseKeys, (objectTimeTreeElements) => { | |
if (objectTimeTreeElements == null || objectTimeTreeElements.Length == 0) { | |
selfPointer._spaceManager.unmarkMemoryElement(theObjectUniverseOrderElement); | |
selfPointer._spaceManager.unmarkMemoryElement(theGlobalUniverseOrderElement); | |
callback(null); | |
} else { | |
long[] closestTimes = new long[times.Length]; | |
ArrayLongLongMap closestUnikTimes = new ArrayLongLongMap(-1, -1, -1, null); | |
ArrayLongLongMap reverseTimeUniverse = new ArrayLongLongMap(-1, -1, -1, null); | |
int nbTimesToload = 0; | |
for (int i = 0; i < times.Length; i++) { | |
int alignedIndexOfUniverse = (int) closestUnikUniverse.get(closestUniverses[i]); | |
closestTimes[i] = ((KLongTree) objectTimeTreeElements[alignedIndexOfUniverse]).previousOrEqual(times[i]); | |
if (!closestUnikTimes.contains(closestTimes[i])) { | |
closestUnikTimes.put(closestTimes[i], nbTimesToload); | |
reverseTimeUniverse.put(closestTimes[i], closestUniverses[i]); | |
nbTimesToload++; | |
} | |
} | |
long[] toLoadTimesKeys = new long[nbTimesToload * 3]; | |
foreach(var entry in closestUnikTimes) { | |
var key = entry.Key; | |
var value = entry.Value; | |
int currentIndex = (int)(value * 3); | |
toLoadTimesKeys[currentIndex] = reverseTimeUniverse.get(key); | |
toLoadTimesKeys[currentIndex + 1] = key; | |
toLoadTimesKeys[currentIndex + 2] = uuid; | |
} | |
selfPointer.getOrLoadAndMarkAll(toLoadTimesKeys, (objectChunks) => { | |
if (objectChunks == null || objectChunks.Length == 0) { | |
selfPointer._spaceManager.unmarkAllMemoryElements(objectTimeTreeElements); | |
selfPointer._spaceManager.unmarkMemoryElement(theObjectUniverseOrderElement); | |
selfPointer._spaceManager.unmarkMemoryElement(theGlobalUniverseOrderElement); | |
callback(null); | |
} else { | |
KObject[] result = new KObject[times.Length]; | |
for (int i = 0; i < times.Length; i++) { | |
long resolvedUniverse = closestUniverses[i]; | |
long resolvedTime = closestTimes[i]; | |
int indexChunks = (int) closestUnikTimes.get(closestTimes[i]); | |
if (indexChunks != -1 && resolvedUniverse != KConfig.NULL_LONG && resolvedTime != KConfig.NULL_LONG) { | |
result[i] = ((AbstractKModel) selfPointer._manager.model()).createProxy(universe, times[i], uuid, selfPointer._manager.model().metaModel().metaClass(((KObjectChunk) objectChunks[indexChunks]).metaClassIndex()), resolvedUniverse, resolvedTime); | |
} else { | |
result[i] = null; | |
} | |
} | |
selfPointer._spaceManager.registerAll(result); | |
callback(result); | |
} | |
}); | |
} | |
}); | |
} | |
}); | |
} | |
}); | |
} catch (Exception e) { | |
//e.printStackTrace(); | |
} | |
}; | |
} | |
public KObjectChunk preciseChunk(long universe, long time, long uuid, KMetaClass metaClass, AtomicReference < long[] > previousResolution) { | |
return internal_chunk(universe, time, uuid, false, metaClass, previousResolution); | |
} | |
public KObjectChunk closestChunk(long universe, long time, long uuid, KMetaClass metaClass, AtomicReference < long[] > previousResolution) { | |
return internal_chunk(universe, time, uuid, true, metaClass, previousResolution); | |
} | |
//TODO optimize the worst case by reusing, by using previous universe cache information, maybe optimize | |
//FIXME | |
private KObjectChunk internal_chunk(long universe, long requestedTime, long uuid, bool useClosest, KMetaClass metaClass, AtomicReference < long[] > previousResolution) { | |
long time = requestedTime; | |
if (metaClass.temporalResolution() != 1) { | |
time = time - (time % metaClass.temporalResolution()); | |
} | |
KObjectChunk currentEntry = (KObjectChunk) _spaceManager.getAndMark(universe, time, uuid); | |
if (currentEntry != null) { | |
long[] previous; | |
long[] current; | |
bool diff = false; | |
do { | |
previous = previousResolution.get(); | |
if (previous[AbstractKObject.UNIVERSE_PREVIOUS_INDEX] != universe || previous[AbstractKObject.TIME_PREVIOUS_INDEX] != time) { | |
current = new long[] { | |
universe, time | |
}; | |
diff = true; | |
} else { | |
current = previous; | |
} | |
} while (!previousResolution.compareAndSet(previous, current)); | |
if (diff) { | |
//we obtains the token, and we have to free the previous one, the new one stay marked | |
_spaceManager.unmark(previous[AbstractKObject.UNIVERSE_PREVIOUS_INDEX], previous[AbstractKObject.TIME_PREVIOUS_INDEX], uuid); | |
} else { | |
_spaceManager.unmarkMemoryElement(currentEntry); | |
} | |
return currentEntry; | |
} | |
KLongLongMap objectUniverseTree = (KLongLongMap) _spaceManager.getAndMark(KConfig.NULL_LONG, KConfig.NULL_LONG, uuid); | |
if (objectUniverseTree == null) { | |
return null; | |
} | |
KLongLongMap globalUniverseTree = (KLongLongMap) _spaceManager.getAndMark(KConfig.NULL_LONG, KConfig.NULL_LONG, KConfig.NULL_LONG); | |
if (globalUniverseTree == null) { | |
_spaceManager.unmarkMemoryElement(objectUniverseTree); | |
return null; | |
} | |
long resolvedUniverse = resolve_universe(globalUniverseTree, objectUniverseTree, time, universe); | |
KLongTree timeTree = (KLongTree) _spaceManager.getAndMark(resolvedUniverse, KConfig.NULL_LONG, uuid); | |
if (timeTree == null) { | |
_spaceManager.unmarkMemoryElement(globalUniverseTree); | |
_spaceManager.unmarkMemoryElement(objectUniverseTree); | |
return null; | |
} | |
long resolvedTime = timeTree.previousOrEqual(time); | |
if (resolvedTime != KConfig.NULL_LONG) { | |
bool needTimeCopy = !useClosest && (resolvedTime != time); | |
bool needUniverseCopy = !useClosest && (resolvedUniverse != universe); | |
currentEntry = (KObjectChunk) _spaceManager.getAndMark(resolvedUniverse, resolvedTime, uuid); | |
if (currentEntry == null) { | |
//TODO cache miss here, we unMark everything used Chunk and go out | |
//System.err.println("DePhasing problem, null chunk unexpected"); | |
_spaceManager.unmarkMemoryElement(timeTree); | |
_spaceManager.unmarkMemoryElement(globalUniverseTree); | |
_spaceManager.unmarkMemoryElement(objectUniverseTree); | |
return null; | |
} | |
if (!needTimeCopy && !needUniverseCopy) { | |
long[] previous; | |
long[] current; | |
bool diff = false; | |
do { | |
previous = previousResolution.get(); | |
if (previous[AbstractKObject.UNIVERSE_PREVIOUS_INDEX] != resolvedUniverse || previous[AbstractKObject.TIME_PREVIOUS_INDEX] != resolvedTime) { | |
current = new long[] { | |
resolvedUniverse, resolvedTime | |
}; | |
diff = true; | |
} else { | |
current = previous; | |
} | |
} while (!previousResolution.compareAndSet(previous, current)); | |
if (diff) { | |
//we obtains the token, and we have to free the previous one | |
_spaceManager.unmark(previous[AbstractKObject.UNIVERSE_PREVIOUS_INDEX], previous[AbstractKObject.TIME_PREVIOUS_INDEX], uuid); | |
} else { | |
_spaceManager.unmarkMemoryElement(currentEntry); | |
} | |
_spaceManager.unmarkMemoryElement(timeTree); | |
_spaceManager.unmarkMemoryElement(globalUniverseTree); | |
_spaceManager.unmarkMemoryElement(objectUniverseTree); | |
return currentEntry; | |
} else { | |
long[] previous; | |
long[] current; | |
bool diff = false; | |
do { | |
previous = previousResolution.get(); | |
if (previous[AbstractKObject.UNIVERSE_PREVIOUS_INDEX] != universe || previous[AbstractKObject.TIME_PREVIOUS_INDEX] != time) { | |
current = new long[] { | |
universe, time | |
}; | |
diff = true; | |
} else { | |
current = previous; | |
} | |
} while (!previousResolution.compareAndSet(previous, current)); | |
if (diff) { | |
KObjectChunk clonedChunk = _spaceManager.cloneAndMark(currentEntry, universe, time, uuid, _manager.model().metaModel()); | |
if (currentEntry.counter() > 2) { //test if we are alone on this chunk or not | |
//double marking strategy | |
currentEntry.addDependency(universe, time, uuid); | |
_spaceManager.markMemoryElement(clonedChunk); | |
} | |
if (!needUniverseCopy) { | |
timeTree.insertKey(time); | |
} else { | |
KLongTree newTemporalTree = (KLongTree) _spaceManager.createAndMark(universe, KConfig.NULL_LONG, uuid, KChunkTypes.LONG_TREE); | |
newTemporalTree.insertKey(time); | |
_spaceManager.unmarkMemoryElement(timeTree); | |
objectUniverseTree.put(universe, time); | |
} | |
//double unmarking, because, we should not use anymore this object | |
_spaceManager.unmarkMemoryElement(currentEntry); | |
_spaceManager.unmarkMemoryElement(currentEntry); | |
//free the rest of used object | |
_spaceManager.unmarkMemoryElement(timeTree); | |
_spaceManager.unmarkMemoryElement(globalUniverseTree); | |
_spaceManager.unmarkMemoryElement(objectUniverseTree); | |
return clonedChunk; | |
} else { | |
//System.err.println("Should not be here !!!!"); | |
_spaceManager.unmarkMemoryElement(timeTree); | |
_spaceManager.unmarkMemoryElement(globalUniverseTree); | |
_spaceManager.unmarkMemoryElement(objectUniverseTree); | |
KObjectChunk waitingChunk = (KObjectChunk) _spaceManager.getAndMark(universe, time, uuid); | |
int i = 0; | |
while (waitingChunk == null && i < KConfig.CAS_MAX_TRY) { | |
waitingChunk = (KObjectChunk) _spaceManager.getAndMark(universe, time, uuid); | |
i++; | |
} | |
if (waitingChunk == null) { | |
throw new Exception("CAS synchronisation problem!"); | |
} else { | |
_spaceManager.unmarkMemoryElement(currentEntry); | |
return waitingChunk; | |
} | |
} | |
} | |
} else { | |
_spaceManager.unmarkMemoryElement(timeTree); | |
_spaceManager.unmarkMemoryElement(globalUniverseTree); | |
_spaceManager.unmarkMemoryElement(objectUniverseTree); | |
return null; | |
} | |
} | |
public void indexObject(KObject obj) { | |
int metaClassIndex = obj.metaClass().index(); | |
KObjectChunk cacheEntry = (KObjectChunk) _spaceManager.createAndMark(obj.universe(), obj.now(), obj.uuid(), KChunkTypes.OBJECT_CHUNK); | |
cacheEntry.init(null, _manager.model().metaModel(), metaClassIndex); | |
cacheEntry.setFlags(KChunkFlags.DIRTY_BIT, 0); | |
cacheEntry.space().declareDirty(cacheEntry); | |
//initiate time management | |
KLongTree timeTree = (KLongTree) _spaceManager.createAndMark(obj.universe(), KConfig.NULL_LONG, obj.uuid(), KChunkTypes.LONG_TREE); | |
timeTree.init(null, _manager.model().metaModel(), metaClassIndex); | |
timeTree.insertKey(obj.now()); | |
//initiate universe management | |
KLongLongMap universeTree = (KLongLongMap) _spaceManager.createAndMark(KConfig.NULL_LONG, KConfig.NULL_LONG, obj.uuid(), KChunkTypes.LONG_LONG_MAP); | |
universeTree.init(null, _manager.model().metaModel(), metaClassIndex); | |
universeTree.put(obj.universe(), obj.now()); | |
_spaceManager.register(obj); | |
} | |
public short typeFromKey(long universe, long time, long uuid) { | |
bool isUniverseNotNull = universe != KConfig.NULL_LONG; | |
short result; | |
if (KConfig.END_OF_TIME == uuid) { | |
if (isUniverseNotNull) { | |
result = KChunkTypes.LONG_LONG_TREE; | |
} else { | |
result = KChunkTypes.LONG_LONG_MAP; | |
} | |
} else { | |
bool isTimeNotNull = time != KConfig.NULL_LONG; | |
bool isObjNotNull = uuid != KConfig.NULL_LONG; | |
if (isUniverseNotNull && isTimeNotNull && isObjNotNull) { | |
result = KChunkTypes.OBJECT_CHUNK; | |
} else if (isUniverseNotNull && !isTimeNotNull && isObjNotNull) { | |
result = KChunkTypes.LONG_TREE; | |
} else { | |
result = KChunkTypes.LONG_LONG_MAP; | |
} | |
} | |
return result; | |
} | |
public void getOrLoadAndMark(long universe, long time, long uuid, KCallback < KChunk > callback) { | |
if (universe == KContentKey.NULL_KEY[0] && time == KContentKey.NULL_KEY[1] && uuid == KContentKey.NULL_KEY[2]) { | |
callback(null); | |
return; | |
} | |
KChunk cached = _spaceManager.getAndMark(universe, time, uuid); | |
if (cached != null) { | |
callback(cached); | |
} else { | |
load(new long[] { | |
universe, time, uuid | |
}, (loadedElements) => callback(loadedElements[0])); | |
} | |
} | |
public void getOrLoadAndMarkAll(long[] keys, KCallback < KChunk[] > callback) { | |
int nbKeys = keys.Length / KEYS_SIZE; | |
bool[] toLoadIndexes = new bool[nbKeys]; | |
int nbElem = 0; | |
KChunk[] result = new KChunk[nbKeys]; | |
for (int i = 0; i < nbKeys; i++) { | |
if (keys[i * KEYS_SIZE] == KContentKey.NULL_KEY[0] && keys[i * KEYS_SIZE + 1] == KContentKey.NULL_KEY[1] && keys[i * KEYS_SIZE + 2] == KContentKey.NULL_KEY[2]) { | |
toLoadIndexes[i] = false; | |
result[i] = null; | |
} else { | |
result[i] = _spaceManager.getAndMark(keys[i * KEYS_SIZE], keys[i * KEYS_SIZE + 1], keys[i * KEYS_SIZE + 2]); | |
if (result[i] == null) { | |
toLoadIndexes[i] = true; | |
nbElem++; | |
} else { | |
toLoadIndexes[i] = false; | |
} | |
} | |
} | |
if (nbElem == 0) { | |
callback(result); | |
} else { | |
long[] keysToLoad = new long[nbElem * 3]; | |
int lastInsertedIndex = 0; | |
for (int i = 0; i < nbKeys; i++) { | |
if (toLoadIndexes[i]) { | |
keysToLoad[lastInsertedIndex] = keys[i * KEYS_SIZE]; | |
lastInsertedIndex++; | |
keysToLoad[lastInsertedIndex] = keys[i * KEYS_SIZE + 1]; | |
lastInsertedIndex++; | |
keysToLoad[lastInsertedIndex] = keys[i * KEYS_SIZE + 2]; | |
lastInsertedIndex++; | |
} | |
} | |
load(keysToLoad, (KChunk[] loadedElements) => { | |
int currentIndexToMerge = 0; | |
for (int i = 0; i < nbKeys; i++) { | |
if (toLoadIndexes[i]) { | |
result[i] = loadedElements[currentIndexToMerge]; | |
currentIndexToMerge++; | |
} | |
} | |
callback(result); | |
}); | |
} | |
} | |
public void getIndex(String metaClassName, long universe, long time, Object[] attrs, KCallback < KObject > callback) { | |
long rootFixedKey = KConfig.END_OF_TIME; | |
getOrLoadAndMark(KConfig.NULL_LONG, KConfig.NULL_LONG, KConfig.NULL_LONG, (KChunk theGlobalUniverseOrderElement) => { | |
if (theGlobalUniverseOrderElement == null) { | |
callback(null); | |
return; | |
} | |
getOrLoadAndMark(KConfig.NULL_LONG, KConfig.NULL_LONG, rootFixedKey, (KChunk rootGlobalUniverseOrderElement) => { | |
if (rootGlobalUniverseOrderElement == null) { | |
_spaceManager.unmarkMemoryElement(theGlobalUniverseOrderElement); | |
callback(null); | |
return; | |
} | |
long closestUniverse = resolve_universe((KLongLongMap) theGlobalUniverseOrderElement, (KLongLongMap) rootGlobalUniverseOrderElement, time, universe); | |
getOrLoadAndMark(closestUniverse, KConfig.NULL_LONG, rootFixedKey, (KChunk theRootTimeTree) => { | |
long resolvedCurrentRootUUID = ((KLongLongTree) theRootTimeTree).previousOrEqualValue(time); | |
_spaceManager.unmarkMemoryElement(theRootTimeTree); | |
_spaceManager.unmarkMemoryElement(rootGlobalUniverseOrderElement); | |
_spaceManager.unmarkMemoryElement(theGlobalUniverseOrderElement); | |
if (resolvedCurrentRootUUID == KConfig.NULL_LONG) { | |
callback(null); | |
} else { | |
_manager.lookup(universe, time, resolvedCurrentRootUUID, callback); | |
} | |
}); | |
}); | |
}); | |
} | |
//TODO, ROOT TREE is NEVER UNLOAD | |
public void getRoot(long universe, long time, KCallback < KObject > callback) { | |
long rootFixedKey = KConfig.END_OF_TIME; | |
getOrLoadAndMark(KConfig.NULL_LONG, KConfig.NULL_LONG, KConfig.NULL_LONG, (KChunk theGlobalUniverseOrderElement) => { | |
if (theGlobalUniverseOrderElement == null) { | |
callback(null); | |
return; | |
} | |
getOrLoadAndMark(KConfig.NULL_LONG, KConfig.NULL_LONG, rootFixedKey, (KChunk rootGlobalUniverseOrderElement) => { | |
if (rootGlobalUniverseOrderElement == null) { | |
_spaceManager.unmarkMemoryElement(theGlobalUniverseOrderElement); | |
callback(null); | |
return; | |
} | |
long closestUniverse = resolve_universe((KLongLongMap) theGlobalUniverseOrderElement, (KLongLongMap) rootGlobalUniverseOrderElement, time, universe); | |
getOrLoadAndMark(closestUniverse, KConfig.NULL_LONG, rootFixedKey, (KChunk theRootTimeTree) => { | |
long resolvedCurrentRootUUID = ((KLongLongTree) theRootTimeTree).previousOrEqualValue(time); | |
_spaceManager.unmarkMemoryElement(theRootTimeTree); | |
_spaceManager.unmarkMemoryElement(rootGlobalUniverseOrderElement); | |
_spaceManager.unmarkMemoryElement(theGlobalUniverseOrderElement); | |
if (resolvedCurrentRootUUID == KConfig.NULL_LONG) { | |
callback(null); | |
} else { | |
_manager.lookup(universe, time, resolvedCurrentRootUUID, callback); | |
} | |
}); | |
}); | |
}); | |
} | |
public void setRoot(KObject newRoot, KCallback < Throwable > callback) { | |
long rootFixedKey = KConfig.END_OF_TIME; | |
getOrLoadAndMark(KConfig.NULL_LONG, KConfig.NULL_LONG, KConfig.NULL_LONG, (KChunk theGlobalUniverseOrderElement) => { | |
if (theGlobalUniverseOrderElement == null) { | |
callback(null); | |
return; | |
} | |
getOrLoadAndMark(KConfig.NULL_LONG, KConfig.NULL_LONG, rootFixedKey, (KChunk rootGlobalUniverseOrderElement) => { | |
KLongLongMap rootGlobalUniverseOrder = (KLongLongMap) rootGlobalUniverseOrderElement; | |
if (rootGlobalUniverseOrderElement == null) { | |
rootGlobalUniverseOrder = (KLongLongMap) _spaceManager.createAndMark(KConfig.NULL_LONG, KConfig.NULL_LONG, KConfig.END_OF_TIME, KChunkTypes.LONG_LONG_MAP); | |
} | |
long closestUniverse = resolve_universe((KLongLongMap) theGlobalUniverseOrderElement, (KLongLongMap) rootGlobalUniverseOrderElement, newRoot.now(), newRoot.universe()); | |
rootGlobalUniverseOrder.put(newRoot.universe(), newRoot.now()); | |
if (closestUniverse != newRoot.universe()) { | |
KLongLongTree newTimeTree = (KLongLongTree) _spaceManager.createAndMark(newRoot.universe(), KConfig.NULL_LONG, KConfig.END_OF_TIME, KChunkTypes.LONG_LONG_TREE); | |
newTimeTree.insert(newRoot.now(), newRoot.uuid()); | |
_spaceManager.unmarkMemoryElement(newTimeTree); | |
_spaceManager.unmarkMemoryElement(rootGlobalUniverseOrderElement); | |
_spaceManager.unmarkMemoryElement(theGlobalUniverseOrderElement); | |
if (callback != null) { | |
callback(null); | |
} | |
} else { | |
getOrLoadAndMark(closestUniverse, KConfig.NULL_LONG, KConfig.END_OF_TIME, (KChunk resolvedRootTimeTree) => { | |
KLongLongTree initializedTree = (KLongLongTree) resolvedRootTimeTree; | |
if (initializedTree == null) { | |
initializedTree = (KLongLongTree) _spaceManager.createAndMark(closestUniverse, KConfig.NULL_LONG, KConfig.END_OF_TIME, KChunkTypes.LONG_LONG_TREE); | |
} | |
initializedTree.insert(newRoot.now(), newRoot.uuid()); | |
_spaceManager.unmarkMemoryElement(resolvedRootTimeTree); | |
_spaceManager.unmarkMemoryElement(rootGlobalUniverseOrderElement); | |
_spaceManager.unmarkMemoryElement(theGlobalUniverseOrderElement); | |
if (callback != null) { | |
callback(null); | |
} | |
}); | |
} | |
}); | |
}); | |
} | |
public void resolveTimes(long currentUniverse, long currentUuid, long startTime, long endTime, KCallback < long[] > callback) { | |
long[] keys = new long[] { | |
KConfig.NULL_LONG, KConfig.NULL_LONG, KConfig.NULL_LONG, | |
KConfig.NULL_LONG, KConfig.NULL_LONG, currentUuid | |
}; | |
getOrLoadAndMarkAll(keys, (KChunk[] kMemoryChunks) => { | |
if (kMemoryChunks == null || kMemoryChunks.Length == 0) { | |
callback(new long[0]); | |
return; | |
} | |
long[] collectedUniverse = universeSelectByRange((KLongLongMap) kMemoryChunks[0], (KLongLongMap) kMemoryChunks[1], startTime, endTime, currentUniverse); | |
int nbKeys = collectedUniverse.Length * 3; | |
long[] timeTreeKeys = new long[nbKeys]; | |
for (int i = 0; i < collectedUniverse.Length; i++) { | |
timeTreeKeys[i * 3] = collectedUniverse[i]; | |
timeTreeKeys[i * 3 + 1] = KConfig.NULL_LONG; | |
timeTreeKeys[i * 3 + 2] = currentUuid; | |
} | |
KLongLongMap objUniverse = (KLongLongMap) kMemoryChunks[1]; | |
getOrLoadAndMarkAll(timeTreeKeys, (KChunk[] timeTrees) => { | |
if (timeTrees == null || timeTrees.Length == 0) { | |
_spaceManager.unmarkAllMemoryElements(kMemoryChunks); | |
callback(new long[0]); | |
return; | |
} | |
ArrayLongLongMap collector = new ArrayLongLongMap(-1, -1, -1, null); | |
long previousDivergenceTime = endTime; | |
for (int i = 0; i < collectedUniverse.Length; i++) { | |
KLongTree timeTree = (KLongTree) timeTrees[i]; | |
if (timeTree != null) { | |
long currentDivergenceTime = objUniverse.get(collectedUniverse[i]); | |
currentDivergenceTime = currentDivergenceTime > startTime ? currentDivergenceTime : startTime; | |
long finalPreviousDivergenceTime = previousDivergenceTime; | |
timeTree.range(currentDivergenceTime, previousDivergenceTime, (t) => { | |
if (collector.size() == 0) { | |
collector.put(collector.size(), t); | |
} else { | |
if (t != finalPreviousDivergenceTime) { | |
collector.put(collector.size(), t); | |
} | |
} | |
}); | |
previousDivergenceTime = currentDivergenceTime; | |
} | |
} | |
long[] orderedTime = new long[collector.size()]; | |
for (int i = 0; i < collector.size(); i++) { | |
orderedTime[i] = collector.get(i); | |
} | |
_spaceManager.unmarkAllMemoryElements(timeTrees); | |
_spaceManager.unmarkAllMemoryElements(kMemoryChunks); | |
callback(orderedTime); | |
}); | |
}); | |
} | |
public static long resolve_universe(KLongLongMap globalTree, KLongLongMap objUniverseTree, long timeToResolve, long originUniverseId) { | |
if (globalTree == null || objUniverseTree == null) { | |
return originUniverseId; | |
} | |
long currentUniverse = originUniverseId; | |
long previousUniverse = KConfig.NULL_LONG; | |
long divergenceTime = objUniverseTree.get(currentUniverse); | |
while (currentUniverse != previousUniverse) { | |
//check range | |
if (divergenceTime != KConfig.NULL_LONG && divergenceTime <= timeToResolve) { | |
return currentUniverse; | |
} | |
//next round | |
previousUniverse = currentUniverse; | |
currentUniverse = globalTree.get(currentUniverse); | |
divergenceTime = objUniverseTree.get(currentUniverse); | |
} | |
return originUniverseId; | |
} | |
public static long[] universeSelectByRange(KLongLongMap globalTree, KLongLongMap objUniverseTree, long rangeMin, long rangeMax, long originUniverseId) { | |
KLongLongMap collected = new ArrayLongLongMap(-1, -1, -1, null); | |
long currentUniverse = originUniverseId; | |
long previousUniverse = KConfig.NULL_LONG; | |
long divergenceTime = objUniverseTree.get(currentUniverse); | |
while (currentUniverse != previousUniverse) { | |
//check range | |
if (divergenceTime != KConfig.NULL_LONG) { | |
if (divergenceTime <= rangeMin) { | |
collected.put(collected.size(), currentUniverse); | |
break; | |
} else if (divergenceTime <= rangeMax) { | |
collected.put(collected.size(), currentUniverse); | |
} | |
} | |
//next round | |
previousUniverse = currentUniverse; | |
currentUniverse = globalTree.get(currentUniverse); | |
divergenceTime = objUniverseTree.get(currentUniverse); | |
} | |
long[] trimmed = new long[collected.size()]; | |
for (long i = 0; i < collected.size(); i++) { | |
trimmed[(int) i] = collected.get(i); | |
} | |
return trimmed; | |
} | |
private void load(long[] keys, KCallback < KChunk[] > callback) { | |
this._manager.cdn().get(keys, (payloads) => { | |
KChunk[] results = new KChunk[keys.Length / 3]; | |
for (int i = 0; i < payloads.Length; i++) { | |
long loopUniverse = keys[i * 3]; | |
long loopTime = keys[i * 3 + 1]; | |
long loopUuid = keys[i * 3 + 2]; | |
results[i] = _spaceManager.createAndMark(loopUniverse, loopTime, loopUuid, typeFromKey(loopUniverse, loopTime, loopUuid)); | |
int classIndex = -1; | |
if (loopUniverse != KConfig.NULL_LONG && loopTime != KConfig.NULL_LONG && loopUuid != KConfig.NULL_LONG) { | |
KLongLongMap alreadyLoadedOrder = (KLongLongMap) _spaceManager.getAndMark(KConfig.NULL_LONG, KConfig.NULL_LONG, loopUuid); | |
if (alreadyLoadedOrder != null) { | |
classIndex = alreadyLoadedOrder.metaClassIndex(); | |
_spaceManager.unmarkMemoryElement(alreadyLoadedOrder); | |
} | |
} | |
results[i].init(payloads[i], _manager.model().metaModel(), classIndex); | |
} | |
callback(results); | |
}); | |
} | |
public int getRelatedKeysResultSize() { | |
return 4; | |
} | |
public void getRelatedKeys(long universe, long time, long uuid, long[] result) { | |
result[0] = universe; | |
result[1] = time; | |
result[2] = uuid; | |
result[3] = universe; | |
result[4] = KConfig.NULL_LONG; | |
result[5] = uuid; | |
result[6] = KConfig.NULL_LONG; | |
result[7] = KConfig.NULL_LONG; | |
result[8] = uuid; | |
result[9] = KConfig.NULL_LONG; | |
result[10] = KConfig.NULL_LONG; | |
result[11] = KConfig.NULL_LONG; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
namespace test | |
{ | |
public delegate void KCallback<T>(T p); | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
namespace test | |
{ | |
public delegate void KTask(); | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
namespace test | |
{ | |
public delegate void KTreeWalker(long t); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment