Skip to content

Commit 4d19c29

Browse files
committed
OAK-4631 - Simplify the format of segments and serialized records
git-svn-id: https://svn.apache.org/repos/asf/jackrabbit/oak/trunk@1757390 13f79535-47bb-0310-9956-ffa450edef68
1 parent f636921 commit 4d19c29

File tree

14 files changed

+509
-868
lines changed

14 files changed

+509
-868
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.jackrabbit.oak.segment;
19+
20+
class BinaryUtils {
21+
22+
private BinaryUtils() {
23+
// Prevent instantiation
24+
}
25+
26+
static int writeByte(byte[] buffer, int position, byte value) {
27+
buffer[position++] = value;
28+
return position;
29+
}
30+
31+
static int writeShort(byte[] buffer, int position, short value) {
32+
position = writeByte(buffer, position, (byte) (value >> 8));
33+
position = writeByte(buffer, position, (byte) (value));
34+
return position;
35+
}
36+
37+
static int writeInt(byte[] buffer, int position, int value) {
38+
position = writeShort(buffer, position, (short) (value >> 16));
39+
position = writeShort(buffer, position, (short) (value));
40+
return position;
41+
}
42+
43+
static int writeLong(byte[] buffer, int position, long value) {
44+
position = writeInt(buffer, position, (int) (value >> 32));
45+
position = writeInt(buffer, position, (int) (value));
46+
return position;
47+
}
48+
49+
}

oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/Segment.java

Lines changed: 72 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import static com.google.common.base.Preconditions.checkNotNull;
2323
import static com.google.common.base.Preconditions.checkPositionIndexes;
2424
import static com.google.common.base.Preconditions.checkState;
25-
import static com.google.common.collect.Lists.newArrayListWithCapacity;
25+
import static com.google.common.collect.Maps.newHashMap;
2626
import static org.apache.jackrabbit.oak.commons.IOUtils.closeQuietly;
2727
import static org.apache.jackrabbit.oak.segment.SegmentId.isDataSegmentId;
2828
import static org.apache.jackrabbit.oak.segment.SegmentVersion.LATEST_VERSION;
@@ -34,7 +34,7 @@
3434
import java.io.StringWriter;
3535
import java.nio.ByteBuffer;
3636
import java.util.Arrays;
37-
import java.util.List;
37+
import java.util.Map;
3838
import java.util.UUID;
3939

4040
import javax.annotation.CheckForNull;
@@ -57,12 +57,14 @@
5757
*/
5858
public class Segment {
5959

60+
static final int HEADER_SIZE = 18;
61+
6062
/**
6163
* Number of bytes used for storing a record identifier. One byte
6264
* is used for identifying the segment and two for the record offset
6365
* within that segment.
6466
*/
65-
static final int RECORD_ID_BYTES = 1 + 2;
67+
static final int RECORD_ID_BYTES = 8 + 8 + 2;
6668

6769
/**
6870
* The limit on segment references within one segment. Since record
@@ -111,12 +113,12 @@ public class Segment {
111113
*/
112114
public static final int BLOB_ID_SMALL_LIMIT = 1 << 12;
113115

114-
public static final int REF_COUNT_OFFSET = 5;
115-
116116
static final int ROOT_COUNT_OFFSET = 6;
117117

118118
public static final int GC_GENERATION_OFFSET = 10;
119119

120+
public static final int REFERENCED_SEGMENT_ID_COUNT_OFFSET = 14;
121+
120122
@Nonnull
121123
private final SegmentStore store;
122124

@@ -135,12 +137,7 @@ public class Segment {
135137
@Nonnull
136138
private final SegmentVersion version;
137139

138-
/**
139-
* Referenced segment identifiers. Entries are initialized lazily in
140-
* {@link #getRefId(int)}. Set to {@code null} for bulk segments.
141-
*/
142-
@CheckForNull
143-
private final SegmentId[] refids;
140+
private final Map<Integer, RecordId> recordIdCache = newHashMap();
144141

145142
/**
146143
* Unpacks a 4 byte aligned segment offset.
@@ -193,11 +190,8 @@ public String toString() {
193190
+ toHex(data.array());
194191
}
195192
});
196-
this.refids = new SegmentId[getRefCount()];
197-
this.refids[0] = id;
198193
this.version = SegmentVersion.fromByte(segmentVersion);
199194
} else {
200-
this.refids = null;
201195
this.version = LATEST_VERSION;
202196
}
203197
}
@@ -223,8 +217,6 @@ private static String toHex(byte[] bytes) {
223217
this.id = store.newDataSegmentId();
224218
this.info = checkNotNull(info);
225219
this.data = ByteBuffer.wrap(checkNotNull(buffer));
226-
this.refids = new SegmentId[SEGMENT_REFERENCE_LIMIT + 1];
227-
this.refids[0] = id;
228220
this.version = SegmentVersion.fromByte(buffer[3]);
229221
id.loaded(this);
230222
}
@@ -253,14 +245,28 @@ public SegmentId getSegmentId() {
253245
return id;
254246
}
255247

256-
int getRefCount() {
257-
return (data.get(REF_COUNT_OFFSET) & 0xff) + 1;
258-
}
259-
260248
public int getRootCount() {
261249
return data.getShort(ROOT_COUNT_OFFSET) & 0xffff;
262250
}
263251

252+
public int getReferencedSegmentIdCount() {
253+
return data.getInt(REFERENCED_SEGMENT_ID_COUNT_OFFSET);
254+
}
255+
256+
public UUID getReferencedSegmentId(int index) {
257+
checkArgument(index < getReferencedSegmentIdCount());
258+
259+
int position = data.position();
260+
261+
position += HEADER_SIZE;
262+
position += index * 16;
263+
264+
long msb = data.getLong(position);
265+
long lsb = data.getLong(position + 8);
266+
267+
return new UUID(msb, lsb);
268+
}
269+
264270
/**
265271
* Determine the gc generation a segment from its data. Note that bulk segments don't have
266272
* generations (i.e. stay at 0).
@@ -285,16 +291,28 @@ public int getGcGeneration() {
285291
}
286292

287293
public RecordType getRootType(int index) {
288-
int refCount = getRefCount();
289294
checkArgument(index < getRootCount());
290-
return RecordType.values()[data.get(data.position() + refCount * 16 + index * 3) & 0xff];
295+
296+
int position = data.position();
297+
298+
position += HEADER_SIZE;
299+
position += getReferencedSegmentIdCount() * 16;
300+
position += index * 3;
301+
302+
return RecordType.values()[data.get(position) & 0xff];
291303
}
292304

293305
public int getRootOffset(int index) {
294-
int refCount = getRefCount();
295306
checkArgument(index < getRootCount());
296-
return (data.getShort(data.position() + refCount * 16 + index * 3 + 1) & 0xffff)
297-
<< RECORD_ALIGN_BITS;
307+
308+
int position = data.position();
309+
310+
position += HEADER_SIZE;
311+
position += getReferencedSegmentIdCount() * 16;
312+
position += index * 3;
313+
position += 1;
314+
315+
return (data.getShort(position) & 0xffff) << RECORD_ALIGN_BITS;
298316
}
299317

300318
private volatile String info;
@@ -316,48 +334,12 @@ public int getRootOffset(int index) {
316334
*/
317335
@CheckForNull
318336
public String getSegmentInfo() {
319-
if (info == null && getRefCount() != 0) {
337+
if (info == null && id.isDataSegmentId()) {
320338
info = readString(getRootOffset(0));
321339
}
322340
return info;
323341
}
324342

325-
SegmentId getRefId(int index) {
326-
if (refids == null || index >= refids.length) {
327-
String type = "data";
328-
if (!id.isDataSegmentId()) {
329-
type = "bulk";
330-
}
331-
long delta = System.currentTimeMillis() - id.getCreationTime();
332-
throw new IllegalStateException("RefId '" + index
333-
+ "' doesn't exist in " + type + " segment " + id
334-
+ ". Creation date delta is " + delta + " ms.");
335-
}
336-
SegmentId refid = refids[index];
337-
if (refid == null) {
338-
synchronized (this) {
339-
refid = refids[index];
340-
if (refid == null) {
341-
int refpos = data.position() + index * 16;
342-
long msb = data.getLong(refpos);
343-
long lsb = data.getLong(refpos + 8);
344-
refid = store.newSegmentId(msb, lsb);
345-
refids[index] = refid;
346-
}
347-
}
348-
}
349-
return refid;
350-
}
351-
352-
public List<SegmentId> getReferencedIds() {
353-
int refcount = getRefCount();
354-
List<SegmentId> ids = newArrayListWithCapacity(refcount);
355-
for (int refid = 0; refid < refcount; refid++) {
356-
ids.add(getRefId(refid));
357-
}
358-
return ids;
359-
}
360-
361343
public int size() {
362344
return data.remaining();
363345
}
@@ -401,9 +383,28 @@ RecordId readRecordId(int offset) {
401383
}
402384

403385
private RecordId internalReadRecordId(int pos) {
404-
SegmentId refid = getRefId(data.get(pos) & 0xff);
405-
int offset = ((data.get(pos + 1) & 0xff) << 8) | (data.get(pos + 2) & 0xff);
406-
return new RecordId(refid, offset << RECORD_ALIGN_BITS);
386+
RecordId recordId = recordIdCache.get(pos);
387+
388+
if (recordId != null) {
389+
return recordId;
390+
}
391+
392+
synchronized (recordIdCache) {
393+
recordId = recordIdCache.get(pos);
394+
395+
if (recordId != null) {
396+
return recordId;
397+
}
398+
399+
long msb = data.getLong(pos);
400+
long lsb = data.getLong(pos + 8);
401+
int offset = (data.getShort(pos + 16) & 0xffff) << RECORD_ALIGN_BITS;
402+
recordId = new RecordId(store.newSegmentId(msb, lsb), offset);
403+
404+
recordIdCache.put(pos, recordId);
405+
406+
return recordId;
407+
}
407408
}
408409

409410
@Nonnull
@@ -538,17 +539,13 @@ public String toString() {
538539
}
539540
if (id.isDataSegmentId()) {
540541
writer.println("--------------------------------------------------------------------------");
541-
int refcount = getRefCount();
542-
for (int refid = 0; refid < refcount; refid++) {
543-
writer.format("reference %02x: %s%n", refid, getRefId(refid));
542+
543+
for (int i = 0; i < getReferencedSegmentIdCount(); i++) {
544+
writer.format("reference %02x: %s%n", i, getReferencedSegmentId(i));
544545
}
545-
int rootcount = data.getShort(ROOT_COUNT_OFFSET) & 0xffff;
546-
int pos = data.position() + refcount * 16;
547-
for (int rootid = 0; rootid < rootcount; rootid++) {
548-
writer.format(
549-
"root %d: %s at %04x%n", rootid,
550-
RecordType.values()[data.get(pos + rootid * 3) & 0xff],
551-
data.getShort(pos + rootid * 3 + 1) & 0xffff);
546+
547+
for (int i = 0; i < getRootCount(); i++) {
548+
writer.format("root %d: %s at %04x%n", i, getRootType(i), getRootOffset(i));
552549
}
553550
}
554551
writer.println("--------------------------------------------------------------------------");

0 commit comments

Comments
 (0)