OffsetHelper class
Пакет: com.hypixel.hytale.storage
Файл: com/hypixel/hytale/storage/IndexedStorageFile.java
Поля (2)
| Модификаторы | Тип | Имя |
|---|---|---|
|
private int |
index |
|
int |
var2 |
Методы (2)
| Модификаторы | Возврат | Сигнатура |
|---|---|---|
|
public int |
lengthpublic int length() |
|
public int |
nextpublic int next(int var1) |
Исходный код
Показать/скрыть
class="kw">package com.hypixel.hytale.storage;
class="kw">import com.github.luben.zstd.Zstd;
class="kw">import com.hypixel.hytale.codec.Codec;
class="kw">import com.hypixel.hytale.metrics.MetricsRegistry;
class="kw">import com.hypixel.hytale.sneakythrow.SneakyThrow;
class="kw">import com.hypixel.hytale.unsafe.UnsafeUtil;
class="kw">import it.unimi.dsi.fastutil.ints.IntArrayList;
class="kw">import it.unimi.dsi.fastutil.ints.IntList;
class="kw">import java.io.Closeable;
class="kw">import java.io.IOException;
class="kw">import java.nio.ByteBuffer;
class="kw">import java.nio.MappedByteBuffer;
class="kw">import java.nio.channels.FileChannel;
class="kw">import java.nio.channels.FileLock;
class="kw">import java.nio.channels.FileChannel.MapMode;
class="kw">import java.nio.charset.StandardCharsets;
class="kw">import java.nio.file.OpenOption;
class="kw">import java.nio.file.Path;
class="kw">import java.nio.file.StandardOpenOption;
class="kw">import java.nio.file.attribute.FileAttribute;
class="kw">import java.util.Arrays;
class="kw">import java.util.BitSet;
class="kw">import java.util.Set;
class="kw">import java.util.concurrent.atomic.AtomicInteger;
class="kw">import java.util.concurrent.locks.StampedLock;
class="kw">import javax.annotation.Nonnull;
class="kw">import javax.annotation.Nullable;
class="kw">public class IndexedStorageFile class="kw">implements Closeable {
class="kw">public class="kw">static class="kw">final StampedLock[] EMPTY_STAMPED_LOCKS = new StampedLock[0];
class="kw">public class="kw">static class="kw">final MetricsRegistry<IndexedStorageFile> METRICS_REGISTRY = new MetricsRegistry<IndexedStorageFile>()
.register("Size", var0 -> {
try {
class="kw">return var0.size();
} catch (IOException var2) {
class="kw">return -1L;
}
}, Codec.LONG)
.register("CompressionLevel", var0 -> var0.getCompressionLevel(), Codec.INTEGER)
.register("BlobCount", var0 -> var0.getBlobCount(), Codec.INTEGER)
.register("UsedBlobCount", SneakyThrow.sneakyFunction(var0 -> var0.usedBlobCount.get()), Codec.INTEGER)
.register("SegmentSize", var0 -> var0.segmentSize(), Codec.INTEGER)
.register("SegmentCount", var0 -> var0.segmentCount(), Codec.INTEGER);
class="kw">public class="kw">static class="kw">final String MAGIC_STRING = "HytaleIndexedStorage";
class="kw">public class="kw">static class="kw">final int VERSION = 1;
class="kw">public class="kw">static class="kw">final int DEFAULT_BLOB_COUNT = 1024;
class="kw">public class="kw">static class="kw">final int DEFAULT_SEGMENT_SIZE = 4096;
class="kw">public class="kw">static class="kw">final int DEFAULT_COMPRESSION_LEVEL = 3;
class="kw">static class="kw">final IndexedStorageFile.OffsetHelper HOH = new IndexedStorageFile.OffsetHelper();
class="kw">public class="kw">static class="kw">final int MAGIC_LENGTH = 20;
class="kw">public class="kw">static class="kw">final int MAGIC_OFFSET = HOH.next(20);
class="kw">public class="kw">static class="kw">final int VERSION_OFFSET = HOH.next(4);
class="kw">public class="kw">static class="kw">final int BLOB_COUNT_OFFSET = HOH.next(4);
class="kw">public class="kw">static class="kw">final int SEGMENT_SIZE_OFFSET = HOH.next(4);
class="kw">public class="kw">static class="kw">final int HEADER_LENGTH = HOH.length();
class="kw">static class="kw">final IndexedStorageFile.OffsetHelper BOH = new IndexedStorageFile.OffsetHelper();
class="kw">public class="kw">static class="kw">final int SRC_LENGTH_OFFSET = BOH.next(4);
class="kw">public class="kw">static class="kw">final int COMPRESSED_LENGTH_OFFSET = BOH.next(4);
class="kw">public class="kw">static class="kw">final int BLOB_HEADER_LENGTH = BOH.length();
class="kw">public class="kw">static class="kw">final int INDEX_SIZE = 4;
class="kw">public class="kw">static class="kw">final int UNASSIGNED_INDEX = 0;
class="kw">public class="kw">static class="kw">final int FIRST_SEGMENT_INDEX = 1;
class="kw">public class="kw">static class="kw">final FileAttribute<?>[] NO_ATTRIBUTES = new FileAttribute[0];
class="kw">static class="kw">final byte[] MAGIC_BYTES = "HytaleIndexedStorage".getBytes(StandardCharsets.UTF_8);
class="kw">private class="kw">static class="kw">final ByteBuffer MAGIC_BUFFER = ByteBuffer.wrap(MAGIC_BYTES);
class="kw">private class="kw">static class="kw">final ThreadLocal<ByteBuffer> CACHED_TEMP_BUFFER = ThreadLocal.withInitial(() -> ByteBuffer.allocateDirect(HEADER_LENGTH));
@Nonnull
class="kw">private class="kw">final Path path;
class="kw">private class="kw">final FileChannel fileChannel;
class="kw">private boolean flushOnWrite = false;
class="kw">private int compressionLevel = 3;
class="kw">private int version;
class="kw">private int blobCount;
class="kw">private int segmentSize;
class="kw">private class="kw">final AtomicInteger usedBlobCount = new AtomicInteger(0);
class="kw">private StampedLock[] indexLocks;
@Nullable
class="kw">private MappedByteBuffer mappedBlobIndexes;
class="kw">private class="kw">final StampedLock segmentLocksLock = new StampedLock();
class="kw">private StampedLock[] segmentLocks = EMPTY_STAMPED_LOCKS;
class="kw">private class="kw">final StampedLock usedSegmentsLock = new StampedLock();
class="kw">private class="kw">final BitSet usedSegments = new BitSet();
@Nonnull
class="kw">private class="kw">static ByteBuffer getTempBuffer(int var0) {
ByteBuffer var1 = CACHED_TEMP_BUFFER.get();
var1.position(0);
var1.limit(var0);
class="kw">return var1;
}
@Nonnull
class="kw">private class="kw">static ByteBuffer allocateDirect(int var0) {
class="kw">return ByteBuffer.allocateDirect(var0);
}
@Nonnull
class="kw">public class="kw">static IndexedStorageFile open(@Nonnull Path var0, OpenOption... var1) class="kw">throws IOException {
class="kw">return open(var0, 1024, 4096, Set.of(var1), NO_ATTRIBUTES);
}
@Nonnull
class="kw">public class="kw">static IndexedStorageFile open(@Nonnull Path var0, @Nonnull Set<? class="kw">extends OpenOption> var1, FileAttribute<?>... var2) class="kw">throws IOException {
class="kw">return open(var0, 1024, 4096, var1, var2);
}
@Nonnull
class="kw">public class="kw">static IndexedStorageFile open(@Nonnull Path var0, int var1, int var2, OpenOption... var3) class="kw">throws IOException {
class="kw">return open(var0, var1, var2, Set.of(var3), NO_ATTRIBUTES);
}
@Nonnull
class="kw">public class="kw">static IndexedStorageFile open(@Nonnull Path var0, int var1, int var2, @Nonnull Set<? class="kw">extends OpenOption> var3, FileAttribute<?>... var4) class="kw">throws IOException {
IndexedStorageFile var5 = new IndexedStorageFile(var0, FileChannel.open(var0, var3, var4));
if (var3.contains(StandardOpenOption.CREATE_NEW)) {
var5.create(var1, var2);
class="kw">return var5;
}
if (var3.contains(StandardOpenOption.CREATE) && var5.fileChannel.size() == 0L) {
var5.create(var1, var2);
} else {
if (var5.fileChannel.size() == 0L) {
throw new IOException("file channel is empty");
}
var5.readHeader();
var5.memoryMapBlobIndexes();
if (var5.version == 0) {
throw new IOException("IndexedStorageFile version 0 is no longer supported");
}
var5.readUsedSegments();
}
class="kw">return var5;
}
class="kw">private IndexedStorageFile(@Nonnull Path var1, @Nonnull FileChannel var2) {
this.path = var1;
this.fileChannel = var2;
}
@Nonnull
class="kw">public Path getPath() {
class="kw">return this.path;
}
class="kw">public int getBlobCount() {
class="kw">return this.blobCount;
}
class="kw">public int getSegmentSize() {
class="kw">return this.segmentSize;
}
class="kw">public int getCompressionLevel() {
class="kw">return this.compressionLevel;
}
class="kw">public int getUsedBlobCount() {
class="kw">return this.usedBlobCount.get();
}
class="kw">public void setFlushOnWrite(boolean var1) {
this.flushOnWrite = var1;
}
class="kw">public void setCompressionLevel(int var1) {
this.compressionLevel = var1;
}
@Nonnull
class="kw">protected IndexedStorageFile create(int var1, int var2) class="kw">throws IOException {
if (var1 <= 0) {
throw new IllegalArgumentException("blobCount must be > 0");
}
if (var2 <= 0) {
throw new IllegalArgumentException("segmentSize must be > 0");
}
this.blobCount = var1;
this.segmentSize = var2;
if (this.fileChannel.size() != 0L) {
throw new IOException("file channel is not empty");
}
this.writeHeader(var1, var2);
this.memoryMapBlobIndexes();
class="kw">return this;
}
class="kw">protected void writeHeader(int var1, int var2) class="kw">throws IOException {
ByteBuffer var3 = getTempBuffer(HEADER_LENGTH);
var3.put(MAGIC_BYTES);
var3.putInt(VERSION_OFFSET, 1);
var3.putInt(BLOB_COUNT_OFFSET, var1);
var3.putInt(SEGMENT_SIZE_OFFSET, var2);
var3.position(0);
if (this.fileChannel.write(var3, 0L) != HEADER_LENGTH) {
throw new IllegalStateException();
}
}
class="kw">protected void readHeader() class="kw">throws IOException {
ByteBuffer var1 = getTempBuffer(HEADER_LENGTH);
if (this.fileChannel.read(var1, 0L) != HEADER_LENGTH) {
throw new IllegalStateException();
}
var1.position(0);
var1.limit(20);
if (!MAGIC_BUFFER.equals(var1)) {
var1.position(0);
byte[] var2 = new byte[20];
var1.get(var2);
throw new IOException("Invalid MAGIC! " + var1 + ", " + Arrays.toString(var2) + " expected " + Arrays.toString(MAGIC_BYTES));
}
var1.limit(HEADER_LENGTH);
this.version = var1.getInt(VERSION_OFFSET);
if (this.version >= 0 && this.version <= 1) {
this.blobCount = var1.getInt(BLOB_COUNT_OFFSET);
this.segmentSize = var1.getInt(SEGMENT_SIZE_OFFSET);
} else {
throw new IOException("Invalid version! " + this.version);
}
}
class="kw">protected void memoryMapBlobIndexes() class="kw">throws IOException {
this.indexLocks = new StampedLock[this.blobCount];
for (int var1 = 0; var1 < this.blobCount; var1++) {
this.indexLocks[var1] = new StampedLock();
}
try {
this.mappedBlobIndexes = this.fileChannel.map(MapMode.READ_WRITE, HEADER_LENGTH, this.blobCount * 4L);
} catch (UnsupportedOperationException var2) {
this.mappedBlobIndexes = null;
}
}
class="kw">protected int getBlobIndex(int var1) class="kw">throws IOException {
int var2 = var1 * 4;
if (this.mappedBlobIndexes == null) {
ByteBuffer var3 = getTempBuffer(4);
if (this.fileChannel.read(var3, HEADER_LENGTH + var2) != 4) {
throw new IllegalStateException();
} else {
class="kw">return var3.getInt(0);
}
} else {
class="kw">return this.mappedBlobIndexes.getInt(var2);
}
}
class="kw">protected void putBlobIndex(int var1, int var2) class="kw">throws IOException {
int var3 = var1 * 4;
if (this.mappedBlobIndexes == null) {
ByteBuffer var4 = getTempBuffer(4);
var4.putInt(0, var2);
if (this.fileChannel.write(var4, HEADER_LENGTH + var3) != 4) {
throw new IllegalStateException();
}
if (this.flushOnWrite) {
this.fileChannel.force(false);
}
} else {
this.mappedBlobIndexes.putInt(var3, var2);
if (this.flushOnWrite) {
this.mappedBlobIndexes.force(var3, 4);
}
}
}
class="kw">protected void readUsedSegments() class="kw">throws IOException {
long var1 = this.usedSegmentsLock.writeLock();
try {
int var3 = 0;
for (int var4 = 0; var4 < this.blobCount; var4++) {
long var7 = this.indexLocks[var4].readLock();
int var5;
int var6;
try {
var5 = this.getBlobIndex(var4);
if (var5 == 0) {
var6 = 0;
} else {
var3++;
ByteBuffer var9 = this.readBlobHeader(var5);
var6 = var9.getInt(COMPRESSED_LENGTH_OFFSET);
}
} class="kw">finally {
this.indexLocks[var4].unlockRead(var7);
}
if (var6 > 0) {
int var18 = this.requiredSegments(BLOB_HEADER_LENGTH + var6);
this.usedSegments.set(var5, var5 + var18);
}
}
this.usedBlobCount.set(var3);
} class="kw">finally {
this.usedSegmentsLock.unlockWrite(var1);
}
}
class="kw">public long size() class="kw">throws IOException {
class="kw">return this.fileChannel.size();
}
class="kw">public int segmentSize() {
try {
class="kw">return this.requiredSegments(this.fileChannel.size() - this.segmentsBase()) + 1;
} catch (IOException var2) {
class="kw">return -1;
}
}
class="kw">public int segmentCount() {
long var1 = this.usedSegmentsLock.tryOptimisticRead();
int var3 = this.usedSegments.cardinality();
if (this.usedSegmentsLock.validate(var1)) {
class="kw">return var3;
}
var1 = this.usedSegmentsLock.readLock();
try {
class="kw">return this.usedSegments.cardinality();
} class="kw">finally {
this.usedSegmentsLock.unlockRead(var1);
}
}
@Nonnull
class="kw">public IntList keys() class="kw">throws IOException {
IntArrayList var1 = new IntArrayList(this.blobCount);
for (int var2 = 0; var2 < this.blobCount; var2++) {
StampedLock var3 = this.indexLocks[var2];
long var4 = var3.tryOptimisticRead();
int var6 = this.getBlobIndex(var2);
if (var3.validate(var4)) {
if (var6 != 0) {
var1.add(var2);
}
} else {
var4 = var3.readLock();
try {
if (this.getBlobIndex(var2) != 0) {
var1.add(var2);
}
} class="kw">finally {
var3.unlockRead(var4);
}
}
}
class="kw">return var1;
}
class="kw">public int readBlobLength(int var1) class="kw">throws IOException {
if (var1 >= 0 && var1 < this.blobCount) {
long var2 = this.indexLocks[var1].readLock();
try {
int var4 = this.getBlobIndex(var1);
if (var4 == 0) {
class="kw">return 0;
}
ByteBuffer var5 = this.readBlobHeader(var4);
class="kw">return var5.getInt(SRC_LENGTH_OFFSET);
} class="kw">finally {
this.indexLocks[var1].unlockRead(var2);
}
} else {
throw new IndexOutOfBoundsException("Index out of range: " + var1 + " blobCount: " + this.blobCount);
}
}
class="kw">public int readBlobCompressedLength(int var1) class="kw">throws IOException {
if (var1 >= 0 && var1 < this.blobCount) {
long var2 = this.indexLocks[var1].readLock();
try {
int var4 = this.getBlobIndex(var1);
if (var4 == 0) {
class="kw">return 0;
}
ByteBuffer var5 = this.readBlobHeader(var4);
class="kw">return var5.getInt(COMPRESSED_LENGTH_OFFSET);
} class="kw">finally {
this.indexLocks[var1].unlockRead(var2);
}
} else {
throw new IndexOutOfBoundsException("Index out of range: " + var1 + " blobCount: " + this.blobCount);
}
}
@Nullable
class="kw">public ByteBuffer readBlob(int var1) class="kw">throws IOException {
if (var1 >= 0 && var1 < this.blobCount) {
long var4 = this.indexLocks[var1].readLock();
ByteBuffer var2;
int var3;
try {
int var6 = this.getBlobIndex(var1);
if (var6 == 0) {
class="kw">return null;
}
ByteBuffer var7 = this.readBlobHeader(var6);
var3 = var7.getInt(SRC_LENGTH_OFFSET);
int var8 = var7.getInt(COMPRESSED_LENGTH_OFFSET);
var2 = this.readSegments(var6, var8);
} class="kw">finally {
this.indexLocks[var1].unlockRead(var4);
}
var2.position(0);
try {
class="kw">return Zstd.decompress(var2, var3);
} class="kw">finally {
if (UnsafeUtil.UNSAFE != null) {
UnsafeUtil.UNSAFE.invokeCleaner(var2);
}
}
} else {
throw new IndexOutOfBoundsException("Index out of range: " + var1 + " blobCount: " + this.blobCount);
}
}
class="kw">public void readBlob(int var1, @Nonnull ByteBuffer var2) class="kw">throws IOException {
if (var1 >= 0 && var1 < this.blobCount) {
long var5 = this.indexLocks[var1].readLock();
ByteBuffer var3;
int var4;
try {
int var7 = this.getBlobIndex(var1);
if (var7 == 0) {
class="kw">return;
}
ByteBuffer var8 = this.readBlobHeader(var7);
var4 = var8.getInt(SRC_LENGTH_OFFSET);
int var9 = var8.getInt(COMPRESSED_LENGTH_OFFSET);
if (var4 > var2.remaining()) {
throw new IllegalArgumentException("dest buffer is not large enough! required dest.remaining() >= " + var4);
}
var3 = this.readSegments(var7, var9);
} class="kw">finally {
this.indexLocks[var1].unlockRead(var5);
}
var3.position(0);
try {
if (var2.isDirect()) {
Zstd.decompress(var2, var3);
} else {
ByteBuffer var25 = allocateDirect(var4);
try {
Zstd.decompress(var25, var3);
var25.position(0);
var2.put(var25);
} class="kw">finally {
if (UnsafeUtil.UNSAFE != null) {
UnsafeUtil.UNSAFE.invokeCleaner(var25);
}
}
}
} class="kw">finally {
if (UnsafeUtil.UNSAFE != null) {
UnsafeUtil.UNSAFE.invokeCleaner(var3);
}
}
} else {
throw new IndexOutOfBoundsException("Index out of range: " + var1 + " blobCount: " + this.blobCount);
}
}
@Nonnull
class="kw">protected ByteBuffer readBlobHeader(int var1) class="kw">throws IOException {
if (var1 == 0) {
throw new IllegalArgumentException("Invalid segment index!");
} else {
ByteBuffer var2 = getTempBuffer(BLOB_HEADER_LENGTH);
if (this.fileChannel.read(var2, this.segmentPosition(var1)) != BLOB_HEADER_LENGTH) {
throw new IllegalStateException();
} else {
class="kw">return var2;
}
}
}
@Nonnull
class="kw">protected ByteBuffer readSegments(int var1, int var2) class="kw">throws IOException {
ByteBuffer var3 = allocateDirect(var2);
long var4 = this.segmentPosition(var1);
if (this.fileChannel.read(var3, var4 + BLOB_HEADER_LENGTH) != var2) {
throw new IllegalStateException();
} else if (var3.remaining() != 0) {
throw new IOException("Failed to read segments: " + var1 + ", " + var2 + ", " + var3);
} else {
class="kw">return var3;
}
}
class="kw">public void writeBlob(int var1, @Nonnull ByteBuffer var2) class="kw">throws IOException {
if (var1 >= 0 && var1 < this.blobCount) {
int var3 = var2.remaining();
int var4 = (int)Zstd.compressBound(var3);
ByteBuffer var5 = allocateDirect(BLOB_HEADER_LENGTH + var4);
try {
var5.putInt(SRC_LENGTH_OFFSET, var3);
var5.position(BLOB_HEADER_LENGTH);
int var6;
if (var2.isDirect()) {
var6 = Zstd.compress(var5, var2, this.compressionLevel);
} else {
ByteBuffer var7 = allocateDirect(var3);
try {
var7.put(var2);
var7.position(0);
var6 = Zstd.compress(var5, var7, this.compressionLevel);
} class="kw">finally {
if (UnsafeUtil.UNSAFE != null) {
UnsafeUtil.UNSAFE.invokeCleaner(var7);
}
}
}
var5.putInt(COMPRESSED_LENGTH_OFFSET, var6);
var5.limit(var5.position());
var5.position(0);
long var37 = this.indexLocks[var1].writeLock();
try {
int var9 = 0;
int var10 = this.getBlobIndex(var1);
if (var10 != 0) {
ByteBuffer var11 = this.readBlobHeader(var10);
int var12 = var11.getInt(COMPRESSED_LENGTH_OFFSET);
var9 = this.requiredSegments(BLOB_HEADER_LENGTH + var12);
}
int var38 = this.writeSegments(var5);
if (this.flushOnWrite) {
this.fileChannel.force(false);
}
this.putBlobIndex(var1, var38);
if (var10 == 0) {
this.usedBlobCount.incrementAndGet();
}
if (var9 > 0) {
long var39 = this.usedSegmentsLock.writeLock();
try {
this.usedSegments.clear(var10, var10 + var9);
} class="kw">finally {
this.usedSegmentsLock.unlockWrite(var39);
}
}
} class="kw">finally {
this.indexLocks[var1].unlockWrite(var37);
}
} class="kw">finally {
if (UnsafeUtil.UNSAFE != null) {
UnsafeUtil.UNSAFE.invokeCleaner(var5);
}
}
} else {
throw new IndexOutOfBoundsException("Index out of range: " + var1 + " blobCount: " + this.blobCount);
}
}
class="kw">public void removeBlob(int var1) class="kw">throws IOException {
if (var1 >= 0 && var1 < this.blobCount) {
long var2 = this.indexLocks[var1].writeLock();
try {
int var4 = this.getBlobIndex(var1);
if (var4 != 0) {
ByteBuffer var5 = this.readBlobHeader(var4);
int var6 = var5.getInt(COMPRESSED_LENGTH_OFFSET);
int var7 = this.requiredSegments(BLOB_HEADER_LENGTH + var6);
this.putBlobIndex(var1, 0);
this.usedBlobCount.decrementAndGet();
long var8 = this.usedSegmentsLock.writeLock();
try {
this.usedSegments.clear(var4, var4 + var7);
} class="kw">finally {
this.usedSegmentsLock.unlockWrite(var8);
}
}
} class="kw">finally {
this.indexLocks[var1].unlockWrite(var2);
}
} else {
throw new IndexOutOfBoundsException("Index out of range: " + var1 + " blobCount: " + this.blobCount);
}
}
class="kw">protected int writeSegments(@Nonnull ByteBuffer var1) class="kw">throws IOException {
int var2 = var1.remaining();
int var3 = this.requiredSegments(var2);
IndexedStorageFile.SegmentRangeWriteLock var4 = this.findFreeSegment(var3);
try {
int var5 = var4.segmentIndex;
if (this.fileChannel.write(var1, this.segmentPosition(var5)) != var2) {
throw new IllegalStateException();
}
long var6 = this.usedSegmentsLock.writeLock();
try {
this.usedSegments.set(var5, var5 + var3);
} class="kw">finally {
this.usedSegmentsLock.unlockWrite(var6);
}
class="kw">return var5;
} class="kw">finally {
var4.unlock();
}
}
@Nonnull
class="kw">private IndexedStorageFile.SegmentRangeWriteLock findFreeSegment(int var1) {
long[] var2 = new long[var1];
int var3 = 1;
label98:
while (true) {
long var4 = this.usedSegmentsLock.readLock();
try {
int var6 = 0;
int var7 = 0;
while (var7 < var1) {
int var8 = this.usedSegments.nextSetBit(var3);
if (var8 < 0) {
var6 = var3;
break;
}
if (var3 == var8) {
var6 = this.usedSegments.nextClearBit(var3);
var8 = this.usedSegments.nextSetBit(var6 + 1);
if (var8 < 0) {
break;
}
var7 = var8 - var6;
var3 = var8 + 1;
} else {
var6 = var3;
var7 = var8 - var6;
var3 = var8 + 1;
}
}
for (int var14 = var1 - 1; var14 >= 0; var14--) {
var2[var14] = this.getSegmentLock(var6 + var14).tryWriteLock();
if (var2[var14] == 0L) {
for (int var9 = var1 - 1; var9 > var14; var9--) {
this.getSegmentLock(var6 + var9).unlockWrite(var2[var9]);
}
var3 = var6 + var14 + 1;
class="kw">continue label98;
}
}
class="kw">return new IndexedStorageFile.SegmentRangeWriteLock(var6, var1, var2);
} class="kw">finally {
this.usedSegmentsLock.unlockRead(var4);
}
}
}
class="kw">protected StampedLock getSegmentLock(int var1) {
if (var1 < this.segmentLocks.length) {
class="kw">return this.segmentLocks[var1];
}
long var2 = this.segmentLocksLock.writeLock();
try {
if (var1 < this.segmentLocks.length) {
class="kw">return this.segmentLocks[var1];
}
int var4 = var1 + 1;
StampedLock[] var5 = Arrays.copyOf(this.segmentLocks, var4);
for (int var6 = this.segmentLocks.length; var6 < var4; var6++) {
var5[var6] = new StampedLock();
}
this.segmentLocks = var5;
class="kw">return this.segmentLocks[var1];
} class="kw">finally {
this.segmentLocksLock.unlockWrite(var2);
}
}
class="kw">protected long segmentsBase() {
class="kw">return HEADER_LENGTH + this.blobCount * 4L;
}
class="kw">protected long segmentOffset(int var1) {
if (var1 == 0) {
throw new IllegalArgumentException("Invalid segment index!");
} else {
class="kw">return (long)(var1 - 1) * this.segmentSize;
}
}
class="kw">protected long segmentPosition(int var1) {
class="kw">return this.segmentOffset(var1) + this.segmentsBase();
}
class="kw">protected int positionToSegment(long var1) {
long var3 = var1 - this.segmentsBase();
if (var3 < 0L) {
throw new IllegalArgumentException("position is before the segments start");
} else {
class="kw">return (int)(var3 / this.segmentSize) + 1;
}
}
class="kw">protected int requiredSegments(long var1) {
class="kw">return (int)((var1 + this.segmentSize - 1L) / this.segmentSize);
}
class="kw">public FileLock lock() class="kw">throws IOException {
class="kw">return this.fileChannel.lock();
}
class="kw">public void force(boolean var1) class="kw">throws IOException {
this.fileChannel.force(var1);
if (this.mappedBlobIndexes != null) {
this.mappedBlobIndexes.force();
}
}
@Override
class="kw">public void close() class="kw">throws IOException {
this.fileChannel.close();
if (UnsafeUtil.UNSAFE != null && this.mappedBlobIndexes != null) {
UnsafeUtil.UNSAFE.invokeCleaner(this.mappedBlobIndexes);
}
this.mappedBlobIndexes = null;
}
@Nonnull
@Override
class="kw">public String toString() {
class="kw">return "IndexedStorageFile{fileChannel="
+ this.fileChannel
+ ", compressionLevel="
+ this.compressionLevel
+ ", blobCount="
+ this.blobCount
+ ", segmentSize="
+ this.segmentSize
+ ", mappedBlobIndexes="
+ this.mappedBlobIndexes
+ ", usedSegments="
+ this.usedSegments
+ "}";
}
class="kw">static {
MAGIC_BUFFER.position(0);
}
class="kw">static class OffsetHelper {
class="kw">private int index;
OffsetHelper() {
}
class="kw">public int next(int var1) {
int var2 = this.index;
this.index += var1;
class="kw">return var2;
}
class="kw">public int length() {
class="kw">return this.index;
}
}
class="kw">protected class SegmentRangeWriteLock {
class="kw">private class="kw">final int segmentIndex;
class="kw">private class="kw">final int count;
class="kw">private class="kw">final long[] stamps;
class="kw">public SegmentRangeWriteLock(int nullx, int nullxx, long[] nullxxx) {
if (nullx == 0) {
throw new IllegalArgumentException("Invalid segment index!");
}
if (nullxx == 0) {
throw new IllegalArgumentException("Invalid count!");
}
this.segmentIndex = nullx;
this.count = nullxx;
this.stamps = nullxxx;
}
class="kw">protected void unlock() {
for (int var1 = 0; var1 < this.count; var1++) {
IndexedStorageFile.this.getSegmentLock(this.segmentIndex + var1).unlockWrite(this.stamps[var1]);
this.stamps[var1] = 0L;
}
}
}
}