private long reserveArrayIndex(Marker from, Marker to) { while (true) { long oldVal = state.get(), marker = from.getMarker(oldVal), delta = from.getDelta(oldVal), rc = from.getRc(oldVal), toMarker = to.getMarker(oldVal), toDelta = to.getDelta(oldVal); if (marker == NO_MARKER) return NO_INDEX; // The list is empty. if (delta == MAX_DELTA) return NO_INDEX; // Too many concurrent operations; spurious failure. if (delta == NO_DELTA) return NO_INDEX; // List is drained and recreated concurrently. if (toDelta == NO_DELTA) { // Same for the OTHER list; spurious. // TODO: the fact that concurrent re-creation of other list necessitates full stop is not // ideal... the reason is that the list NOT being re-created still uses the list // being re-created for boundary check; it needs the old value of the other marker. // However, NO_DELTA means the other marker was already set to a new value. For now, // assume concurrent re-creation is rare and the gap before commit is tiny. return NO_INDEX; } assert rc <= delta; // There can never be more concurrent takers than uncommitted ones. long newDelta = incDeltaValue(marker, toMarker, delta); // Increase target list pos. if (newDelta == NO_DELTA) return NO_INDEX; // Target list is being drained. long newVal = from.setRc(from.setDelta(oldVal, newDelta), rc + 1); // Set delta and refcount. if (setState(oldVal, newVal)) return oldVal; } }
private void commitArrayIndex(Marker from, Marker to, long originalMarker) { while (true) { long oldVal = state.get(), rc = from.getRc(oldVal); long newVal = from.setRc(oldVal, rc - 1); // Decrease refcount. assert rc > 0; if (rc == 1) { // We are the last of the concurrent operations to finish. Commit. long marker = from.getMarker(oldVal), delta = from.getDelta(oldVal), otherMarker = to.getMarker(oldVal), otherDelta = to.getDelta(oldVal); assert rc <= delta; // Move marker according to delta, change delta to 0. long newMarker = applyDeltaToMarker(marker, otherMarker, delta); newVal = from.setDelta(from.setMarker(newVal, newMarker), 0); if (otherMarker == NO_MARKER) { // The other list doesn't exist, create it at the first index of our op. assert otherDelta == 0; newVal = to.setMarker(newVal, originalMarker); } else if (otherDelta > 0 && otherDelta != NO_DELTA && applyDeltaToMarker(otherMarker, marker, otherDelta) == NO_MARKER) { // The other list will be exhausted when it commits. Create new one pending that commit. newVal = to.setDelta(to.setMarker(newVal, originalMarker), NO_DELTA); } } if (setState(oldVal, newVal)) return; } }
private long reserveArrayIndex(Marker from, Marker to) { while (true) { long oldVal = state.get(), marker = from.getMarker(oldVal), delta = from.getDelta(oldVal), rc = from.getRc(oldVal), toMarker = to.getMarker(oldVal), toDelta = to.getDelta(oldVal); if (marker == NO_MARKER) return NO_INDEX; // The list is empty. if (delta == MAX_DELTA) return NO_INDEX; // Too many concurrent operations; spurious failure. if (delta == NO_DELTA) return NO_INDEX; // List is drained and recreated concurrently. if (toDelta == NO_DELTA) { // Same for the OTHER list; spurious. // TODO: the fact that concurrent re-creation of other list necessitates full stop is not // ideal... the reason is that the list NOT being re-created still uses the list // being re-created for boundary check; it needs the old value of the other marker. // However, NO_DELTA means the other marker was already set to a new value. For now, // assume concurrent re-creation is rare and the gap before commit is tiny. return NO_INDEX; } assert rc <= delta; // There can never be more concurrent takers than uncommitted ones. long newDelta = incDeltaValue(marker, toMarker, delta); // Increase target list pos. if (newDelta == NO_DELTA) return NO_INDEX; // Target list is being drained. long newVal = from.setRc(from.setDelta(oldVal, newDelta), rc + 1); // Set delta and refcount. if (setState(oldVal, newVal)) return oldVal; } }
private void commitArrayIndex(Marker from, Marker to, long originalMarker) { while (true) { long oldVal = state.get(), rc = from.getRc(oldVal); long newVal = from.setRc(oldVal, rc - 1); // Decrease refcount. assert rc > 0; if (rc == 1) { // We are the last of the concurrent operations to finish. Commit. long marker = from.getMarker(oldVal), delta = from.getDelta(oldVal), otherMarker = to.getMarker(oldVal), otherDelta = to.getDelta(oldVal); assert rc <= delta; // Move marker according to delta, change delta to 0. long newMarker = applyDeltaToMarker(marker, otherMarker, delta); newVal = from.setDelta(from.setMarker(newVal, newMarker), 0); if (otherMarker == NO_MARKER) { // The other list doesn't exist, create it at the first index of our op. assert otherDelta == 0; newVal = to.setMarker(newVal, originalMarker); } else if (otherDelta > 0 && otherDelta != NO_DELTA && applyDeltaToMarker(otherMarker, marker, otherDelta) == NO_MARKER) { // The other list will be exhausted when it commits. Create new one pending that commit. newVal = to.setDelta(to.setMarker(newVal, originalMarker), NO_DELTA); } } if (setState(oldVal, newVal)) return; } }