/** * Sets the block id, data and auxData for the block at (x, y, z), if the current data matches the * expected data.<br> * * @param x the x coordinate * @param y the y coordinate * @param z the z coordinate * @param expectId the expected block id * @param expectData the expected block data * @param expectAuxData the expected block auxiliary data * @param newId the new block id * @param newData the new block data * @param newAuxData the new block auxiliary data * @return true if the block was set */ @Override public boolean compareAndSetBlock( int x, int y, int z, short expectId, short expectData, short newId, short newData) { int index = getIndex(x, y, z); int spins = 0; boolean interrupted = false; try { while (true) { if (spins++ > SPINS) { interrupted |= atomicWait(index); } checkCompressing(); short oldBlockId = blockIds.get(index); boolean oldReserved = auxStore.isReserved(oldBlockId); if (!oldReserved) { if (blockIds.get(index) != expectId || expectData != 0) { return false; } } else { int seq = auxStore.getSequence(oldBlockId); short oldId = auxStore.getId(oldBlockId); short oldData = auxStore.getData(oldBlockId); if (!testSequence(x, y, z, seq)) { continue; } if (oldId != expectId || oldData != expectData) { return false; } } if (newData == 0 && !auxStore.isReserved(newId)) { if (!blockIds.compareAndSet(index, oldBlockId, newId)) { continue; } } else { int newIndex = auxStore.add(newId, newData); if (!blockIds.compareAndSet(index, oldBlockId, (short) newIndex)) { auxStore.remove(newIndex); continue; } } if (oldReserved) { auxStore.remove(oldBlockId); } markDirty(x, y, z); return true; } } finally { atomicNotify(index); if (interrupted) { Thread.currentThread().interrupt(); } } }
/** * Compresses the auxiliary store.<br> * <br> * This method should only be called when the store is guaranteed not to be accessed from any * other thread.<br> */ @Override public void compress() { if (!compressing.compareAndSet(false, true)) { throw new IllegalStateException("Compression started while compression was in progress"); } int length = side * side * side; AtomicIntArrayStore newAuxStore = new AtomicIntArrayStore(length); for (int i = 0; i < length; i++) { short blockId = blockIds.get(i); if (auxStore.isReserved(blockId)) { short storedId = auxStore.getId(blockId); short storedData = auxStore.getData(blockId); int newIndex = newAuxStore.add(storedId, storedData); if (!blockIds.compareAndSet(i, blockId, (short) newIndex)) { throw new IllegalStateException("Unstable block id data during compression step"); } } } auxStore = newAuxStore; compressing.set(false); }
private int getAndSetBlockRaw(int x, int y, int z, short id, short data) { int index = getIndex(x, y, z); int spins = 0; boolean interrupted = false; try { while (true) { if (spins++ > SPINS) { interrupted |= atomicWait(index); } checkCompressing(); short oldBlockId = blockIds.get(index); boolean oldReserved = auxStore.isReserved(oldBlockId); if (data == 0 && !auxStore.isReserved(id)) { if (!blockIds.compareAndSet(index, oldBlockId, id)) { continue; } } else { int newIndex = auxStore.add(id, data); if (!blockIds.compareAndSet(index, oldBlockId, (short) newIndex)) { auxStore.remove(newIndex); continue; } } if (oldReserved) { return auxStore.remove(oldBlockId); } return BlockFullState.getPacked(oldBlockId, (short) 0); } } finally { markDirty(x, y, z); atomicNotify(index); if (interrupted) { Thread.currentThread().interrupt(); } } }