-
Notifications
You must be signed in to change notification settings - Fork 218
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Resharding: Consumer-side support for list, set, map types
Showing
75 changed files
with
3,937 additions
and
1,531 deletions.
There are no files selected for viewing
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
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
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
23 changes: 23 additions & 0 deletions
23
hollow/src/main/java/com/netflix/hollow/core/read/engine/HollowTypeDataElements.java
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package com.netflix.hollow.core.read.engine; | ||
|
||
import com.netflix.hollow.core.memory.MemoryMode; | ||
import com.netflix.hollow.core.memory.encoding.GapEncodedVariableLengthIntegerReader; | ||
import com.netflix.hollow.core.memory.pool.ArraySegmentRecycler; | ||
|
||
public abstract class HollowTypeDataElements { | ||
|
||
public int maxOrdinal; | ||
|
||
public GapEncodedVariableLengthIntegerReader encodedAdditions; | ||
public GapEncodedVariableLengthIntegerReader encodedRemovals; | ||
|
||
public final ArraySegmentRecycler memoryRecycler; | ||
public final MemoryMode memoryMode; | ||
|
||
public HollowTypeDataElements(MemoryMode memoryMode, ArraySegmentRecycler memoryRecycler) { | ||
this.memoryMode = memoryMode; | ||
this.memoryRecycler = memoryRecycler; | ||
} | ||
|
||
public abstract void destroy(); | ||
} |
75 changes: 75 additions & 0 deletions
75
hollow/src/main/java/com/netflix/hollow/core/read/engine/HollowTypeDataElementsJoiner.java
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package com.netflix.hollow.core.read.engine; | ||
|
||
import com.netflix.hollow.core.memory.encoding.GapEncodedVariableLengthIntegerReader; | ||
|
||
public abstract class HollowTypeDataElementsJoiner<T extends HollowTypeDataElements> { | ||
public final int fromMask; | ||
public final int fromOrdinalShift; | ||
public final T[] from; | ||
|
||
public T to; | ||
|
||
public HollowTypeDataElementsJoiner(T[] from) { | ||
this.from = from; | ||
this.fromMask = from.length - 1; | ||
this.fromOrdinalShift = 31 - Integer.numberOfLeadingZeros(from.length); | ||
|
||
if (from.length<=0 || !((from.length&(from.length-1))==0)) { | ||
throw new IllegalStateException("No. of DataElements to be joined must be a power of 2"); | ||
} | ||
|
||
for (int i=0;i<from.length;i++) { | ||
if (from[i].maxOrdinal == -1) { | ||
continue; | ||
} | ||
if (from[i].maxOrdinal > (1<<29) | ||
|| from[i].maxOrdinal != 0 && (from.length > (1<<29)/from[i].maxOrdinal) | ||
|| from[i].maxOrdinal * from.length + i > (1<<29)) { | ||
throw new IllegalArgumentException("Too large to join, maxOrdinal would exceed 2<<29"); | ||
} | ||
} | ||
|
||
for (HollowTypeDataElements elements : from) { | ||
if (elements.encodedAdditions != null) { | ||
throw new IllegalStateException("Encountered encodedAdditions in data elements joiner- this is not expected " + | ||
"since encodedAdditions only exist on delta data elements and they dont carry over to target data elements, " + | ||
"delta data elements are never split/joined"); | ||
} | ||
} | ||
} | ||
|
||
public T join() { | ||
|
||
initToElements(); | ||
to.maxOrdinal = -1; | ||
|
||
populateStats(); | ||
|
||
copyRecords(); | ||
|
||
GapEncodedVariableLengthIntegerReader[] fromRemovals = new GapEncodedVariableLengthIntegerReader[from.length]; | ||
for (int i=0;i<from.length;i++) { | ||
fromRemovals[i] = from[i].encodedRemovals; | ||
} | ||
to.encodedRemovals = GapEncodedVariableLengthIntegerReader.join(fromRemovals); | ||
|
||
return to; | ||
} | ||
|
||
/** | ||
* Initialize the target data elements. | ||
*/ | ||
public abstract void initToElements(); | ||
|
||
/** | ||
* Populate the stats of the target data elements. | ||
*/ | ||
public abstract void populateStats(); | ||
|
||
/** | ||
* Copy records from the source data elements to the target data elements. | ||
*/ | ||
public abstract void copyRecords(); | ||
|
||
|
||
} |
73 changes: 73 additions & 0 deletions
73
hollow/src/main/java/com/netflix/hollow/core/read/engine/HollowTypeDataElementsSplitter.java
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package com.netflix.hollow.core.read.engine; | ||
|
||
import com.netflix.hollow.core.memory.encoding.GapEncodedVariableLengthIntegerReader; | ||
|
||
/** | ||
* Join multiple {@code HollowListTypeDataElements}s into 1 {@code HollowListTypeDataElements}. | ||
* Ordinals are remapped and corresponding data is copied over. | ||
* The original data elements are not destroyed. | ||
* The no. of passed data elements must be a power of 2. | ||
*/ | ||
public abstract class HollowTypeDataElementsSplitter<T extends HollowTypeDataElements> { | ||
public final int numSplits; | ||
public final int toMask; | ||
public final int toOrdinalShift; | ||
public final T from; | ||
|
||
public T[] to; | ||
|
||
public HollowTypeDataElementsSplitter(T from, int numSplits) { | ||
this.from = from; | ||
this.numSplits = numSplits; | ||
this.toMask = numSplits - 1; | ||
this.toOrdinalShift = 31 - Integer.numberOfLeadingZeros(numSplits); | ||
|
||
if (numSplits<=0 || !((numSplits&(numSplits-1))==0)) { | ||
throw new IllegalStateException("Must split by power of 2"); | ||
} | ||
|
||
if (from.encodedAdditions != null) { | ||
throw new IllegalStateException("Encountered encodedAdditions in data elements splitter- this is not expected " + | ||
"since encodedAdditions only exist on delta data elements and they dont carry over to target data elements, " + | ||
"delta data elements are never split/joined"); | ||
} | ||
} | ||
|
||
public T[] split() { | ||
|
||
initToElements(); | ||
for(int i=0;i<to.length;i++) { | ||
to[i].maxOrdinal = -1; | ||
} | ||
|
||
populateStats(); | ||
|
||
copyRecords(); | ||
|
||
if (from.encodedRemovals != null) { | ||
GapEncodedVariableLengthIntegerReader[] splitRemovals = from.encodedRemovals.split(numSplits); | ||
for(int i=0;i<to.length;i++) { | ||
to[i].encodedRemovals = splitRemovals[i]; | ||
} | ||
} | ||
|
||
return to; | ||
} | ||
|
||
/** | ||
* Initialize the target data elements. | ||
*/ | ||
public abstract void initToElements(); | ||
|
||
/** | ||
* Populate the stats of the target data elements. | ||
*/ | ||
public abstract void populateStats(); | ||
|
||
/** | ||
* Copy records from the source data elements to the target data elements. | ||
*/ | ||
public abstract void copyRecords(); | ||
|
||
|
||
} |
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
8 changes: 8 additions & 0 deletions
8
hollow/src/main/java/com/netflix/hollow/core/read/engine/HollowTypeReadStateShard.java
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package com.netflix.hollow.core.read.engine; | ||
|
||
public interface HollowTypeReadStateShard { | ||
|
||
HollowTypeDataElements getDataElements(); | ||
|
||
int getShardOrdinalShift(); | ||
} |
191 changes: 191 additions & 0 deletions
191
hollow/src/main/java/com/netflix/hollow/core/read/engine/HollowTypeReshardingStrategy.java
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
package com.netflix.hollow.core.read.engine; | ||
|
||
import com.netflix.hollow.core.read.engine.list.HollowListTypeReadState; | ||
import com.netflix.hollow.core.read.engine.list.HollowListTypeReshardingStrategy; | ||
import com.netflix.hollow.core.read.engine.map.HollowMapTypeReadState; | ||
import com.netflix.hollow.core.read.engine.map.HollowMapTypeReshardingStrategy; | ||
import com.netflix.hollow.core.read.engine.object.HollowObjectTypeReadState; | ||
import com.netflix.hollow.core.read.engine.object.HollowObjectTypeReshardingStrategy; | ||
import com.netflix.hollow.core.read.engine.set.HollowSetTypeReadState; | ||
import com.netflix.hollow.core.read.engine.set.HollowSetTypeReshardingStrategy; | ||
import java.util.Arrays; | ||
|
||
public abstract class HollowTypeReshardingStrategy { | ||
private final static HollowTypeReshardingStrategy OBJECT_RESHARDING_STRATEGY = new HollowObjectTypeReshardingStrategy(); | ||
private final static HollowTypeReshardingStrategy LIST_RESHARDING_STRATEGY = new HollowListTypeReshardingStrategy(); | ||
private final static HollowTypeReshardingStrategy SET_RESHARDING_STRATEGY = new HollowSetTypeReshardingStrategy(); | ||
private final static HollowTypeReshardingStrategy MAP_RESHARDING_STRATEGY = new HollowMapTypeReshardingStrategy(); | ||
|
||
public abstract HollowTypeDataElementsSplitter createDataElementsSplitter(HollowTypeDataElements from, int shardingFactor); | ||
|
||
public abstract HollowTypeDataElementsJoiner createDataElementsJoiner(HollowTypeDataElements[] from); | ||
|
||
public static HollowTypeReshardingStrategy getInstance(HollowTypeReadState typeState) { | ||
if (typeState instanceof HollowObjectTypeReadState) { | ||
return OBJECT_RESHARDING_STRATEGY; | ||
} else if (typeState instanceof HollowListTypeReadState) { | ||
return LIST_RESHARDING_STRATEGY; | ||
} else if (typeState instanceof HollowSetTypeReadState) { | ||
return SET_RESHARDING_STRATEGY; | ||
} else if (typeState instanceof HollowMapTypeReadState) { | ||
return MAP_RESHARDING_STRATEGY; | ||
} else { | ||
throw new IllegalArgumentException("Unsupported type state: " + typeState.getClass().getName()); | ||
} | ||
} | ||
|
||
/** | ||
* Reshards this type state to the desired shard count using O(shard size) space while supporting concurrent reads | ||
* into the underlying data elements. | ||
* | ||
* @param typeState The type state to reshard | ||
* @param prevNumShards The current number of shards in typeState | ||
* @param newNumShards The desired number of shards for typeState | ||
*/ | ||
public void reshard(HollowTypeReadState typeState, int prevNumShards, int newNumShards) { | ||
int shardingFactor = shardingFactor(prevNumShards, newNumShards); | ||
HollowTypeDataElements[] newDataElements; | ||
int[] shardOrdinalShifts; | ||
|
||
try { | ||
if (newNumShards > prevNumShards) { // split existing shards | ||
// Step 1: Grow the number of shards. Each original shard will result in N child shards where N is the sharding factor. | ||
// The child shards will reference into the existing data elements as-is, and reuse existing shardOrdinalShift. | ||
// However since the shards array is resized, a read will map into the new shard index, as a result a subset of | ||
// ordinals in each shard will be accessed. In the next "splitting" step, the data elements in these new shards | ||
// will be filtered to only retain the subset of ordinals that are actually accessed. | ||
// | ||
// This is an atomic update to shardsVolatile: full construction happens-before the store to shardsVolatile, | ||
// in other words a fully constructed object as visible to this thread will be visible to other threads that | ||
// load the new shardsVolatile. | ||
typeState.updateShardsVolatile(expandWithOriginalDataElements(typeState.getShardsVolatile(), shardingFactor)); | ||
|
||
// Step 2: Split each original data element into N child data elements where N is the sharding factor. | ||
// Then update each of the N child shards with the respective split of data element, this will be | ||
// sufficient to serve all reads into this shard. Once all child shards for a pre-split parent | ||
// shard have been assigned the split data elements, the parent data elements can be discarded. | ||
for (int i = 0; i < prevNumShards; i++) { | ||
HollowTypeDataElements originalDataElements = typeState.getShardsVolatile().getShards()[i].getDataElements(); | ||
|
||
typeState.updateShardsVolatile(splitDataElementsForOneShard(typeState, i, prevNumShards, shardingFactor)); | ||
|
||
typeState.destroyOriginalDataElements(originalDataElements); | ||
} | ||
// Re-sharding done. | ||
// shardsVolatile now contains newNumShards shards where each shard contains | ||
// a split of original data elements. | ||
|
||
} else { // join existing shards | ||
// Step 1: Join N data elements to create one, where N is the sharding factor. Then update each of the | ||
// N shards to reference the joined result, but with a new shardOrdinalShift. | ||
// Reads will continue to reference the same shard index as before, but the new shardOrdinalShift | ||
// will help these reads land at the right ordinal in the joined shard. When all N old shards | ||
// corresponding to one new shard have been updated, the N pre-join data elements can be destroyed. | ||
for (int i = 0; i < newNumShards; i++) { | ||
HollowTypeDataElements destroyCandidates[] = joinCandidates(typeState, i, shardingFactor); | ||
|
||
typeState.updateShardsVolatile(joinDataElementsForOneShard(typeState, i, shardingFactor)); // atomic update to shardsVolatile | ||
|
||
for (int j = 0; j < shardingFactor; j++) { | ||
typeState.destroyOriginalDataElements(destroyCandidates[j]); | ||
} | ||
} | ||
|
||
// Step 2: Resize the shards array to only keep the first newNumShards shards. | ||
newDataElements = typeState.createTypeDataElements(typeState.getShardsVolatile().getShards().length); | ||
shardOrdinalShifts = new int[typeState.getShardsVolatile().getShards().length]; | ||
copyShardDataElements(typeState.getShardsVolatile(), newDataElements, shardOrdinalShifts); | ||
|
||
HollowTypeReadStateShard[] newShards = Arrays.copyOfRange(typeState.getShardsVolatile().getShards(), 0, newNumShards); | ||
typeState.updateShardsVolatile(newShards); | ||
|
||
// Re-sharding done. | ||
// shardsVolatile now contains newNumShards shards where each shard contains | ||
// a join of original data elements. | ||
} | ||
} catch (Exception e) { | ||
throw new RuntimeException("Error in re-sharding", e); | ||
} | ||
} | ||
|
||
/** | ||
* Given old and new numShards, this method returns the shard resizing multiplier. | ||
*/ | ||
public static int shardingFactor(int oldNumShards, int newNumShards) { | ||
if (newNumShards <= 0 || oldNumShards <= 0 || newNumShards == oldNumShards) { | ||
throw new IllegalStateException("Invalid shard resizing, oldNumShards=" + oldNumShards + ", newNumShards=" + newNumShards); | ||
} | ||
|
||
boolean isNewGreater = newNumShards > oldNumShards; | ||
int dividend = isNewGreater ? newNumShards : oldNumShards; | ||
int divisor = isNewGreater ? oldNumShards : newNumShards; | ||
|
||
if (dividend % divisor != 0) { | ||
throw new IllegalStateException("Invalid shard resizing, oldNumShards=" + oldNumShards + ", newNumShards=" + newNumShards); | ||
} | ||
return dividend / divisor; | ||
} | ||
|
||
private void copyShardDataElements(ShardsHolder from, HollowTypeDataElements[] newDataElements, int[] shardOrdinalShifts) { | ||
for (int i=0; i<from.getShards().length; i++) { | ||
newDataElements[i] = from.getShards()[i].getDataElements(); | ||
shardOrdinalShifts[i] = from.getShards()[i].getShardOrdinalShift(); | ||
} | ||
} | ||
|
||
private HollowTypeDataElements[] joinCandidates(HollowTypeReadState typeState, int indexIntoShards, int shardingFactor) { | ||
HollowTypeReadStateShard[] shards = typeState.getShardsVolatile().getShards(); | ||
HollowTypeDataElements[] result = typeState.createTypeDataElements(shardingFactor); | ||
int newNumShards = shards.length / shardingFactor; | ||
for (int i=0; i<shardingFactor; i++) { | ||
result[i] = shards[indexIntoShards + (newNumShards*i)].getDataElements(); | ||
} | ||
return result; | ||
} | ||
|
||
public HollowTypeReadStateShard[] joinDataElementsForOneShard(HollowTypeReadState typeState, int currentIndex, int shardingFactor) { | ||
ShardsHolder shardsHolder = typeState.getShardsVolatile(); | ||
int newNumShards = shardsHolder.getShards().length / shardingFactor; | ||
int newShardOrdinalShift = 31 - Integer.numberOfLeadingZeros(newNumShards); | ||
|
||
HollowTypeDataElements[] joinCandidates = joinCandidates(typeState, currentIndex, shardingFactor); | ||
HollowTypeDataElementsJoiner joiner = createDataElementsJoiner(joinCandidates); | ||
HollowTypeDataElements joined = joiner.join(); | ||
|
||
HollowTypeReadStateShard[] newShards = Arrays.copyOf(shardsHolder.getShards(), shardsHolder.getShards().length); | ||
for (int i=0; i<shardingFactor; i++) { | ||
newShards[currentIndex + (newNumShards*i)] = typeState.createTypeReadStateShard(typeState.getSchema(), joined, newShardOrdinalShift); | ||
} | ||
|
||
return newShards; | ||
} | ||
|
||
public HollowTypeReadStateShard[] expandWithOriginalDataElements(ShardsHolder shardsHolder, int shardingFactor) { | ||
int prevNumShards = shardsHolder.getShards().length; | ||
int newNumShards = prevNumShards * shardingFactor; | ||
HollowTypeReadStateShard[] newShards = new HollowTypeReadStateShard[newNumShards]; | ||
|
||
for(int i=0; i<prevNumShards; i++) { | ||
for (int j=0; j<shardingFactor; j++) { | ||
newShards[i+(prevNumShards*j)] = shardsHolder.getShards()[i]; | ||
} | ||
} | ||
return newShards; | ||
} | ||
|
||
public HollowTypeReadStateShard[] splitDataElementsForOneShard(HollowTypeReadState typeState, int currentIndex, int prevNumShards, int shardingFactor) { | ||
ShardsHolder shardsHolder = typeState.getShardsVolatile(); | ||
int newNumShards = shardsHolder.getShards().length; | ||
int newShardOrdinalShift = 31 - Integer.numberOfLeadingZeros(newNumShards); | ||
|
||
HollowTypeDataElements dataElementsToSplit = shardsHolder.getShards()[currentIndex].getDataElements(); | ||
HollowTypeDataElementsSplitter splitter = createDataElementsSplitter(dataElementsToSplit, shardingFactor); | ||
HollowTypeDataElements[] splits = splitter.split(); | ||
|
||
HollowTypeReadStateShard[] newShards = Arrays.copyOf(shardsHolder.getShards(), shardsHolder.getShards().length); | ||
for (int i = 0; i < shardingFactor; i ++) { | ||
newShards[currentIndex + (prevNumShards*i)] = typeState.createTypeReadStateShard(typeState.getSchema(), splits[i], newShardOrdinalShift); | ||
} | ||
return newShards; | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
hollow/src/main/java/com/netflix/hollow/core/read/engine/ShardsHolder.java
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.netflix.hollow.core.read.engine; | ||
|
||
public abstract class ShardsHolder { | ||
|
||
public abstract HollowTypeReadStateShard[] getShards(); | ||
|
||
public abstract int getShardNumberMask(); | ||
|
||
} |
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
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
73 changes: 73 additions & 0 deletions
73
.../main/java/com/netflix/hollow/core/read/engine/list/HollowListTypeDataElementsJoiner.java
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package com.netflix.hollow.core.read.engine.list; | ||
|
||
import com.netflix.hollow.core.memory.FixedLengthDataFactory; | ||
import com.netflix.hollow.core.read.engine.HollowTypeDataElementsJoiner; | ||
|
||
|
||
/** | ||
* Join multiple {@code HollowListTypeDataElements}s into 1 {@code HollowListTypeDataElements}. | ||
* Ordinals are remapped and corresponding data is copied over. | ||
* The original data elements are not destroyed. | ||
* The no. of passed data elements must be a power of 2. | ||
*/ | ||
class HollowListTypeDataElementsJoiner extends HollowTypeDataElementsJoiner<HollowListTypeDataElements> { | ||
|
||
public HollowListTypeDataElementsJoiner(HollowListTypeDataElements[] from) { | ||
super(from); | ||
} | ||
|
||
@Override | ||
public void initToElements() { | ||
this.to = new HollowListTypeDataElements(from[0].memoryMode, from[0].memoryRecycler); | ||
} | ||
|
||
@Override | ||
public void populateStats() { | ||
for(int fromIndex=0;fromIndex<from.length;fromIndex++) { | ||
int mappedMaxOrdinal = from[fromIndex].maxOrdinal == -1 ? -1 : (from[fromIndex].maxOrdinal * from.length) + fromIndex; | ||
to.maxOrdinal = Math.max(to.maxOrdinal, mappedMaxOrdinal); | ||
if (from[fromIndex].bitsPerElement > to.bitsPerElement) { | ||
// uneven bitsPerElement could be the case for consumers that skip type shards with no additions, so pick max across all shards | ||
to.bitsPerElement = from[fromIndex].bitsPerElement; | ||
} | ||
} | ||
|
||
long totalOfListSizes = 0; | ||
for(int ordinal=0;ordinal<=to.maxOrdinal;ordinal++) { | ||
int fromIndex = ordinal & fromMask; | ||
int fromOrdinal = ordinal >> fromOrdinalShift; | ||
|
||
long startElement = from[fromIndex].getStartElement(fromOrdinal); | ||
long endElement = from[fromIndex].getEndElement(fromOrdinal); | ||
long numElements = endElement - startElement; | ||
totalOfListSizes += numElements; | ||
|
||
} | ||
to.bitsPerListPointer = totalOfListSizes == 0 ? 1 : 64 - Long.numberOfLeadingZeros(totalOfListSizes); | ||
to.totalNumberOfElements = totalOfListSizes; | ||
} | ||
|
||
@Override | ||
public void copyRecords() { | ||
long elementCounter = 0; | ||
|
||
to.listPointerData = FixedLengthDataFactory.get((long)to.bitsPerListPointer * (to.maxOrdinal + 1), to.memoryMode, to.memoryRecycler); | ||
to.elementData = FixedLengthDataFactory.get(to.bitsPerElement * to.totalNumberOfElements, to.memoryMode, to.memoryRecycler); | ||
|
||
for(int ordinal=0;ordinal<=to.maxOrdinal;ordinal++) { | ||
int fromIndex = ordinal & fromMask; | ||
int fromOrdinal = ordinal >> fromOrdinalShift; | ||
|
||
if (fromOrdinal <= from[fromIndex].maxOrdinal) { // else lopsided shard for e.g. when consumers skip type shards with no additions | ||
HollowListTypeDataElements source = from[fromIndex]; | ||
long startElement = source.getStartElement(fromOrdinal); | ||
long endElement = source.getEndElement(fromOrdinal); | ||
|
||
long numElements = endElement - startElement; | ||
to.copyElementsFrom(elementCounter, source, startElement, endElement); | ||
elementCounter += numElements; | ||
} | ||
to.listPointerData.setElementValue((long)to.bitsPerListPointer * ordinal, to.bitsPerListPointer, elementCounter); | ||
} | ||
} | ||
} |
83 changes: 83 additions & 0 deletions
83
...ain/java/com/netflix/hollow/core/read/engine/list/HollowListTypeDataElementsSplitter.java
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package com.netflix.hollow.core.read.engine.list; | ||
|
||
import com.netflix.hollow.core.memory.FixedLengthDataFactory; | ||
import com.netflix.hollow.core.read.engine.HollowTypeDataElementsSplitter; | ||
|
||
/** | ||
* Split a {@code HollowListTypeDataElements} into multiple {@code HollowListTypeDataElements}s. | ||
* Ordinals are remapped and corresponding data is copied over. | ||
* The original data elements are not destroyed. | ||
* {@code numSplits} must be a power of 2. | ||
*/ | ||
public class HollowListTypeDataElementsSplitter extends HollowTypeDataElementsSplitter<HollowListTypeDataElements> { | ||
|
||
public HollowListTypeDataElementsSplitter(HollowListTypeDataElements from, int numSplits) { | ||
super(from, numSplits); | ||
} | ||
|
||
@Override | ||
public void initToElements() { | ||
this.to = new HollowListTypeDataElements[numSplits]; | ||
for(int i=0;i<to.length;i++) { | ||
to[i] = new HollowListTypeDataElements(from.memoryMode, from.memoryRecycler); | ||
} | ||
} | ||
|
||
@Override | ||
public void populateStats() { | ||
long[] totalOfListSizes = new long[numSplits]; | ||
|
||
// count elements per split | ||
for(int ordinal=0;ordinal<=from.maxOrdinal;ordinal++) { | ||
int toIndex = ordinal & toMask; | ||
int toOrdinal = ordinal >> toOrdinalShift; | ||
to[toIndex].maxOrdinal = toOrdinal; | ||
|
||
long startElement = from.getStartElement(ordinal); | ||
long endElement = from.getEndElement(ordinal); | ||
long numElements = endElement - startElement; | ||
totalOfListSizes[toIndex] += numElements; | ||
} | ||
|
||
long maxShardTotalOfListSizes = 0; | ||
for(int toIndex=0;toIndex<numSplits;toIndex++) { | ||
if(totalOfListSizes[toIndex] > maxShardTotalOfListSizes) | ||
maxShardTotalOfListSizes = totalOfListSizes[toIndex]; | ||
} | ||
|
||
for(int toIndex=0;toIndex<numSplits;toIndex++) { | ||
HollowListTypeDataElements target = to[toIndex]; | ||
target.bitsPerElement = from.bitsPerElement; // retained | ||
target.bitsPerListPointer = maxShardTotalOfListSizes == 0 ? 1 : 64 - Long.numberOfLeadingZeros(maxShardTotalOfListSizes); | ||
target.totalNumberOfElements = totalOfListSizes[toIndex]; // useful for heap usage stats | ||
} | ||
} | ||
|
||
@Override | ||
public void copyRecords() { | ||
int numSplits = to.length; | ||
long elementCounter[] = new long[numSplits]; | ||
|
||
for(int toIndex=0;toIndex<numSplits;toIndex++) { | ||
HollowListTypeDataElements target = to[toIndex]; | ||
target.listPointerData = FixedLengthDataFactory.get((long)target.bitsPerListPointer * (target.maxOrdinal + 1), target.memoryMode, target.memoryRecycler); | ||
target.elementData = FixedLengthDataFactory.get(target.bitsPerElement * target.totalNumberOfElements, target.memoryMode, target.memoryRecycler); | ||
} | ||
|
||
// count elements per split | ||
for(int ordinal=0;ordinal<=from.maxOrdinal;ordinal++) { | ||
int toIndex = ordinal & toMask; | ||
int toOrdinal = ordinal >> toOrdinalShift; | ||
|
||
long startElement = from.getStartElement(ordinal); | ||
long endElement = from.getEndElement(ordinal); | ||
HollowListTypeDataElements target = to[toIndex]; | ||
|
||
long numElements = endElement - startElement; | ||
target.copyElementsFrom(elementCounter[toIndex], from, startElement, endElement); | ||
elementCounter[toIndex] += numElements; | ||
|
||
target.listPointerData.setElementValue((long)target.bitsPerListPointer * toOrdinal, target.bitsPerListPointer, elementCounter[toIndex]); | ||
} | ||
} | ||
} |
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
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
18 changes: 18 additions & 0 deletions
18
.../main/java/com/netflix/hollow/core/read/engine/list/HollowListTypeReshardingStrategy.java
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package com.netflix.hollow.core.read.engine.list; | ||
|
||
import com.netflix.hollow.core.read.engine.HollowTypeDataElements; | ||
import com.netflix.hollow.core.read.engine.HollowTypeDataElementsJoiner; | ||
import com.netflix.hollow.core.read.engine.HollowTypeDataElementsSplitter; | ||
import com.netflix.hollow.core.read.engine.HollowTypeReshardingStrategy; | ||
|
||
public class HollowListTypeReshardingStrategy extends HollowTypeReshardingStrategy { | ||
@Override | ||
public HollowTypeDataElementsSplitter createDataElementsSplitter(HollowTypeDataElements from, int shardingFactor) { | ||
return new HollowListTypeDataElementsSplitter((HollowListTypeDataElements) from, shardingFactor); | ||
} | ||
|
||
@Override | ||
public HollowTypeDataElementsJoiner createDataElementsJoiner(HollowTypeDataElements[] from) { | ||
return new HollowListTypeDataElementsJoiner((HollowListTypeDataElements[]) from); | ||
} | ||
} |
52 changes: 52 additions & 0 deletions
52
...ow/src/main/java/com/netflix/hollow/core/read/engine/list/HollowListTypeShardsHolder.java
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package com.netflix.hollow.core.read.engine.list; | ||
|
||
import com.netflix.hollow.core.read.engine.HollowTypeReadStateShard; | ||
import com.netflix.hollow.core.read.engine.ShardsHolder; | ||
|
||
public class HollowListTypeShardsHolder extends ShardsHolder { | ||
final HollowListTypeReadStateShard shards[]; | ||
final int shardNumberMask; | ||
|
||
/** | ||
* Thread safe construction of ShardHolder with given shards | ||
* @param fromShards shards to be used | ||
*/ | ||
public HollowListTypeShardsHolder(HollowTypeReadStateShard[] fromShards) { | ||
this.shards = new HollowListTypeReadStateShard[fromShards.length]; | ||
for (int i=0; i<fromShards.length; i++) { | ||
this.shards[i] = (HollowListTypeReadStateShard) fromShards[i]; | ||
} | ||
this.shardNumberMask = fromShards.length - 1; | ||
} | ||
|
||
/** | ||
* Thread safe construction of a ShardHolder which has all the shards from {@code oldShards} except | ||
* the shard at index {@code newShardIndex}, using the shard {@code newShard} at that index instead. | ||
* @param oldShards original shards | ||
* @param newShard a new shard | ||
* @param newShardIndex index at which to place the new shard | ||
*/ | ||
HollowListTypeShardsHolder(HollowListTypeReadStateShard[] oldShards, HollowListTypeReadStateShard newShard, int newShardIndex) { | ||
int numShards = oldShards.length; | ||
HollowListTypeReadStateShard[] shards = new HollowListTypeReadStateShard[numShards]; | ||
for (int i=0; i<numShards; i++) { | ||
if (i == newShardIndex) { | ||
shards[i] = newShard; | ||
} else { | ||
shards[i] = oldShards[i]; | ||
} | ||
} | ||
this.shards = shards; | ||
this.shardNumberMask = numShards - 1; | ||
} | ||
|
||
@Override | ||
public HollowTypeReadStateShard[] getShards() { | ||
return shards; | ||
} | ||
|
||
@Override | ||
public int getShardNumberMask() { | ||
return shardNumberMask; | ||
} | ||
} |
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
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
92 changes: 92 additions & 0 deletions
92
...rc/main/java/com/netflix/hollow/core/read/engine/map/HollowMapTypeDataElementsJoiner.java
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
package com.netflix.hollow.core.read.engine.map; | ||
|
||
import com.netflix.hollow.core.memory.FixedLengthDataFactory; | ||
import com.netflix.hollow.core.read.engine.HollowTypeDataElementsJoiner; | ||
|
||
|
||
/** | ||
* Join multiple {@code HollowMapTypeDataElements}s into 1 {@code HollowMapTypeDataElements}. | ||
* Ordinals are remapped and corresponding data is copied over. | ||
* The original data elements are not destroyed. | ||
* The no. of passed data elements must be a power of 2. | ||
*/ | ||
class HollowMapTypeDataElementsJoiner extends HollowTypeDataElementsJoiner<HollowMapTypeDataElements> { | ||
|
||
public HollowMapTypeDataElementsJoiner(HollowMapTypeDataElements[] from) { | ||
super(from); | ||
} | ||
|
||
@Override | ||
public void initToElements() { | ||
this.to = new HollowMapTypeDataElements(from[0].memoryMode, from[0].memoryRecycler); | ||
} | ||
|
||
@Override | ||
public void populateStats() { | ||
for(int fromIndex=0;fromIndex<from.length;fromIndex++) { | ||
int mappedMaxOrdinal = from[fromIndex].maxOrdinal == -1 ? -1 : (from[fromIndex].maxOrdinal * from.length) + fromIndex; | ||
to.maxOrdinal = Math.max(to.maxOrdinal, mappedMaxOrdinal); | ||
|
||
// uneven stats could be the case for consumers that skip type shards with no additions, so pick max across all shards | ||
HollowMapTypeDataElements source = from[fromIndex]; | ||
if (source.bitsPerKeyElement > to.bitsPerKeyElement) { | ||
to.bitsPerKeyElement = source.bitsPerKeyElement; | ||
} | ||
if (source.bitsPerValueElement > to.bitsPerValueElement) { | ||
to.bitsPerValueElement = source.bitsPerValueElement; | ||
} | ||
if (source.bitsPerMapSizeValue > to.bitsPerMapSizeValue) { | ||
to.bitsPerMapSizeValue = source.bitsPerMapSizeValue; | ||
} | ||
} | ||
to.emptyBucketKeyValue = (1 << to.bitsPerKeyElement) - 1; | ||
|
||
long totalOfMapBuckets = 0; | ||
for(int ordinal=0;ordinal<=to.maxOrdinal;ordinal++) { | ||
int fromIndex = ordinal & fromMask; | ||
int fromOrdinal = ordinal >> fromOrdinalShift; | ||
|
||
HollowMapTypeDataElements source = from[fromIndex]; | ||
|
||
long startBucket = source.getStartBucket(fromOrdinal); | ||
long endBucket = source.getEndBucket(fromOrdinal); | ||
long numBuckets = endBucket - startBucket; | ||
|
||
totalOfMapBuckets += numBuckets; | ||
} | ||
|
||
to.totalNumberOfBuckets = totalOfMapBuckets; | ||
to.bitsPerMapPointer = 64 - Long.numberOfLeadingZeros(to.totalNumberOfBuckets); | ||
to.bitsPerFixedLengthMapPortion = to.bitsPerMapSizeValue + to.bitsPerMapPointer; | ||
to.bitsPerMapEntry = to.bitsPerKeyElement + to.bitsPerValueElement; | ||
} | ||
|
||
@Override | ||
public void copyRecords() { | ||
long bucketCounter = 0; | ||
|
||
to.mapPointerAndSizeData = FixedLengthDataFactory.get((long)(to.maxOrdinal + 1) * to.bitsPerFixedLengthMapPortion, to.memoryMode, to.memoryRecycler); | ||
to.entryData = FixedLengthDataFactory.get(to.totalNumberOfBuckets * to.bitsPerMapEntry, to.memoryMode, to.memoryRecycler); | ||
|
||
for(int ordinal=0;ordinal<=to.maxOrdinal;ordinal++) { | ||
int fromIndex = ordinal & fromMask; | ||
int fromOrdinal = ordinal >> fromOrdinalShift; | ||
|
||
HollowMapTypeDataElements source = from[fromIndex]; | ||
|
||
long mapSize = 0; | ||
if (fromOrdinal <= from[fromIndex].maxOrdinal) { // else lopsided shards resulting from skipping type shards with no additions, mapSize remains 0 | ||
long startBucket = source.getStartBucket(fromOrdinal); | ||
long endBucket = source.getEndBucket(fromOrdinal); | ||
|
||
long numBuckets = endBucket - startBucket; | ||
to.copyBucketsFrom(bucketCounter, source, startBucket, endBucket); | ||
bucketCounter += numBuckets; | ||
|
||
mapSize = source.mapPointerAndSizeData.getElementValue((long)(fromOrdinal * source.bitsPerFixedLengthMapPortion) + source.bitsPerMapPointer, source.bitsPerMapSizeValue); | ||
} | ||
to.mapPointerAndSizeData.setElementValue( (long)ordinal * to.bitsPerFixedLengthMapPortion, to.bitsPerMapPointer, bucketCounter); | ||
to.mapPointerAndSizeData.setElementValue((long)(ordinal * to.bitsPerFixedLengthMapPortion) + to.bitsPerMapPointer, to.bitsPerMapSizeValue, mapSize); | ||
} | ||
} | ||
} |
91 changes: 91 additions & 0 deletions
91
.../main/java/com/netflix/hollow/core/read/engine/map/HollowMapTypeDataElementsSplitter.java
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package com.netflix.hollow.core.read.engine.map; | ||
|
||
|
||
import com.netflix.hollow.core.memory.FixedLengthDataFactory; | ||
import com.netflix.hollow.core.read.engine.HollowTypeDataElementsSplitter; | ||
|
||
/** | ||
* Split a {@code HollowMapTypeDataElements} into multiple {@code HollowMapTypeDataElements}s. | ||
* Ordinals are remapped and corresponding data is copied over. | ||
* The original data elements are not destroyed. | ||
* {@code numSplits} must be a power of 2. | ||
*/ | ||
public class HollowMapTypeDataElementsSplitter extends HollowTypeDataElementsSplitter<HollowMapTypeDataElements> { | ||
|
||
public HollowMapTypeDataElementsSplitter(HollowMapTypeDataElements from, int numSplits) { | ||
super(from, numSplits); | ||
} | ||
|
||
@Override | ||
public void initToElements() { | ||
this.to = new HollowMapTypeDataElements[numSplits]; | ||
for(int i=0;i<to.length;i++) { | ||
to[i] = new HollowMapTypeDataElements(from.memoryMode, from.memoryRecycler); | ||
} | ||
} | ||
|
||
@Override | ||
public void populateStats() { | ||
long[] shardTotalOfMapBuckets = new long[numSplits]; | ||
long maxShardTotalOfMapBuckets = 0; | ||
|
||
for(int ordinal=0;ordinal<=from.maxOrdinal;ordinal++) { | ||
int toIndex = ordinal & toMask; | ||
int toOrdinal = ordinal >> toOrdinalShift; | ||
to[toIndex].maxOrdinal = toOrdinal; | ||
|
||
long startBucket = from.getStartBucket(ordinal); | ||
long endBucket = from.getEndBucket(ordinal); | ||
long numBuckets = endBucket - startBucket; | ||
|
||
shardTotalOfMapBuckets[toIndex] += numBuckets; | ||
if(shardTotalOfMapBuckets[toIndex] > maxShardTotalOfMapBuckets) { | ||
maxShardTotalOfMapBuckets = shardTotalOfMapBuckets[toIndex]; | ||
} | ||
} | ||
|
||
for(int toIndex=0;toIndex<numSplits;toIndex++) { | ||
HollowMapTypeDataElements target = to[toIndex]; | ||
// retained | ||
target.bitsPerKeyElement = from.bitsPerKeyElement; | ||
target.bitsPerValueElement = from.bitsPerValueElement; | ||
target.bitsPerMapSizeValue = from.bitsPerMapSizeValue; | ||
target.emptyBucketKeyValue = from.emptyBucketKeyValue; | ||
|
||
// recomputed | ||
target.bitsPerMapPointer = 64 - Long.numberOfLeadingZeros(maxShardTotalOfMapBuckets); | ||
target.totalNumberOfBuckets = shardTotalOfMapBuckets[toIndex]; | ||
target.bitsPerFixedLengthMapPortion = target.bitsPerMapSizeValue + target.bitsPerMapPointer; | ||
target.bitsPerMapEntry = target.bitsPerKeyElement + target.bitsPerValueElement; | ||
} | ||
} | ||
|
||
@Override | ||
public void copyRecords() { | ||
int numSplits = to.length; | ||
long bucketCounter[] = new long[numSplits]; | ||
|
||
for(int toIndex=0;toIndex<numSplits;toIndex++) { | ||
HollowMapTypeDataElements target = to[toIndex]; | ||
target.mapPointerAndSizeData = FixedLengthDataFactory.get((long)(target.maxOrdinal + 1) * target.bitsPerFixedLengthMapPortion, target.memoryMode, target.memoryRecycler); | ||
target.entryData = FixedLengthDataFactory.get(target.totalNumberOfBuckets * target.bitsPerMapEntry, target.memoryMode, target.memoryRecycler); | ||
} | ||
|
||
for(int ordinal=0;ordinal<=from.maxOrdinal;ordinal++) { | ||
int toIndex = ordinal & toMask; | ||
int toOrdinal = ordinal >> toOrdinalShift; | ||
|
||
HollowMapTypeDataElements target = to[toIndex]; | ||
long startBucket = from.getStartBucket(ordinal); | ||
long endBucket = from.getEndBucket(ordinal); | ||
|
||
long numBuckets = endBucket - startBucket; | ||
target.copyBucketsFrom(bucketCounter[toIndex], from, startBucket, endBucket); | ||
bucketCounter[toIndex] += numBuckets; | ||
|
||
target.mapPointerAndSizeData.setElementValue((long)toOrdinal * target.bitsPerFixedLengthMapPortion, target.bitsPerMapPointer, bucketCounter[toIndex]); | ||
long mapSize = from.mapPointerAndSizeData.getElementValue((long)(ordinal * from.bitsPerFixedLengthMapPortion) + from.bitsPerMapPointer, from.bitsPerMapSizeValue); | ||
target.mapPointerAndSizeData.setElementValue((long)(toOrdinal * target.bitsPerFixedLengthMapPortion) + target.bitsPerMapPointer, target.bitsPerMapSizeValue, mapSize); | ||
} | ||
} | ||
} |
302 changes: 223 additions & 79 deletions
302
hollow/src/main/java/com/netflix/hollow/core/read/engine/map/HollowMapTypeReadState.java
Large diffs are not rendered by default.
Oops, something went wrong.
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
18 changes: 18 additions & 0 deletions
18
...rc/main/java/com/netflix/hollow/core/read/engine/map/HollowMapTypeReshardingStrategy.java
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package com.netflix.hollow.core.read.engine.map; | ||
|
||
import com.netflix.hollow.core.read.engine.HollowTypeDataElements; | ||
import com.netflix.hollow.core.read.engine.HollowTypeDataElementsJoiner; | ||
import com.netflix.hollow.core.read.engine.HollowTypeDataElementsSplitter; | ||
import com.netflix.hollow.core.read.engine.HollowTypeReshardingStrategy; | ||
|
||
public class HollowMapTypeReshardingStrategy extends HollowTypeReshardingStrategy { | ||
@Override | ||
public HollowTypeDataElementsSplitter createDataElementsSplitter(HollowTypeDataElements from, int shardingFactor) { | ||
return new HollowMapTypeDataElementsSplitter((HollowMapTypeDataElements) from, shardingFactor); | ||
} | ||
|
||
@Override | ||
public HollowTypeDataElementsJoiner createDataElementsJoiner(HollowTypeDataElements[] from) { | ||
return new HollowMapTypeDataElementsJoiner((HollowMapTypeDataElements[]) from); | ||
} | ||
} |
52 changes: 52 additions & 0 deletions
52
hollow/src/main/java/com/netflix/hollow/core/read/engine/map/HollowMapTypeShardsHolder.java
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package com.netflix.hollow.core.read.engine.map; | ||
|
||
import com.netflix.hollow.core.read.engine.HollowTypeReadStateShard; | ||
import com.netflix.hollow.core.read.engine.ShardsHolder; | ||
|
||
public class HollowMapTypeShardsHolder extends ShardsHolder { | ||
final HollowMapTypeReadStateShard shards[]; | ||
final int shardNumberMask; | ||
|
||
/** | ||
* Thread safe construction of ShardHolder with given shards | ||
* @param fromShards shards to be used | ||
*/ | ||
public HollowMapTypeShardsHolder(HollowTypeReadStateShard[] fromShards) { | ||
this.shards = new HollowMapTypeReadStateShard[fromShards.length]; | ||
for (int i=0; i<fromShards.length; i++) { | ||
this.shards[i] = (HollowMapTypeReadStateShard) fromShards[i]; | ||
} | ||
this.shardNumberMask = fromShards.length - 1; | ||
} | ||
|
||
/** | ||
* Thread safe construction of a ShardHolder which has all the shards from {@code oldShards} except | ||
* the shard at index {@code newShardIndex}, using the shard {@code newShard} at that index instead. | ||
* @param oldShards original shards | ||
* @param newShard a new shard | ||
* @param newShardIndex index at which to place the new shard | ||
*/ | ||
HollowMapTypeShardsHolder(HollowMapTypeReadStateShard[] oldShards, HollowMapTypeReadStateShard newShard, int newShardIndex) { | ||
int numShards = oldShards.length; | ||
HollowMapTypeReadStateShard[] shards = new HollowMapTypeReadStateShard[numShards]; | ||
for (int i=0; i<numShards; i++) { | ||
if (i == newShardIndex) { | ||
shards[i] = newShard; | ||
} else { | ||
shards[i] = oldShards[i]; | ||
} | ||
} | ||
this.shards = shards; | ||
this.shardNumberMask = numShards - 1; | ||
} | ||
|
||
@Override | ||
public HollowTypeReadStateShard[] getShards() { | ||
return shards; | ||
} | ||
|
||
@Override | ||
public int getShardNumberMask() { | ||
return shardNumberMask; | ||
} | ||
} |
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
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
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
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
Oops, something went wrong.