Index: src/main/java/org/apache/jackrabbit/oak/plugins/segment/RecordUsageAnalyser.java
===================================================================
--- src/main/java/org/apache/jackrabbit/oak/plugins/segment/RecordUsageAnalyser.java (revision 1660580)
+++ src/main/java/org/apache/jackrabbit/oak/plugins/segment/RecordUsageAnalyser.java (working copy)
@@ -224,13 +224,31 @@
}
// Recurse into properties
- int ids = template.getChildName() == ZERO_CHILD_NODES ? 1 : 2;
- nodeSize += ids * RECORD_ID_BYTES;
PropertyTemplate[] propertyTemplates = template.getPropertyTemplates();
- for (PropertyTemplate propertyTemplate : propertyTemplates) {
- nodeSize += RECORD_ID_BYTES;
- RecordId propertyId = segment.readRecordId(offset + ids++ * RECORD_ID_BYTES);
- analyseProperty(propertyId, propertyTemplate);
+ if (segment.getStorageFormatVersion() == Segment.STORAGE_FORMAT_VERSION) {
+ if (propertyTemplates.length > 0) {
+ int ids = template.getChildName() == ZERO_CHILD_NODES ? 1 : 2;
+ nodeSize += ids * RECORD_ID_BYTES;
+
+ nodeSize += RECORD_ID_BYTES;
+ RecordId id = segment.readRecordId(offset + ids * RECORD_ID_BYTES);
+ analyseList(id, propertyTemplates.length);
+ ListRecord pIds = new ListRecord(id,
+ propertyTemplates.length);
+ for (int i = 0; i < propertyTemplates.length; i++) {
+ RecordId propertyId = pIds.getEntry(i);
+ analyseProperty(propertyId, propertyTemplates[i]);
+ }
+ }
+ } else {
+ int ids = template.getChildName() == ZERO_CHILD_NODES ? 1 : 2;
+ nodeSize += ids * RECORD_ID_BYTES;
+ for (PropertyTemplate propertyTemplate : propertyTemplates) {
+ nodeSize += RECORD_ID_BYTES;
+ RecordId propertyId = segment.readRecordId(offset + ids++
+ * RECORD_ID_BYTES);
+ analyseProperty(propertyId, propertyTemplate);
+ }
}
}
}
@@ -295,11 +313,27 @@
size += Segment.RECORD_ID_BYTES;
}
- for (int i = 0; i < propertyCount; i++) {
- RecordId propertyNameId = segment.readRecordId(offset + size);
- size += Segment.RECORD_ID_BYTES;
- size++; // type
- analyseString(propertyNameId);
+ if (segment.getStorageFormatVersion() == Segment.STORAGE_FORMAT_VERSION) {
+ // read storage format as V11
+ if (propertyCount > 0) {
+ RecordId listId = segment.readRecordId(offset + size);
+ analyseList(listId, propertyCount);
+ size += Segment.RECORD_ID_BYTES;
+ ListRecord propertyNames = new ListRecord(listId, propertyCount);
+ for (int i = 0; i < propertyCount; i++) {
+ RecordId propertyNameId = propertyNames.getEntry(i);
+ size++; // type
+ analyseString(propertyNameId);
+ }
+ }
+ } else {
+ // read storage format as V10
+ for (int i = 0; i < propertyCount; i++) {
+ RecordId propertyNameId = segment.readRecordId(offset + size);
+ size += Segment.RECORD_ID_BYTES;
+ size++; // type
+ analyseString(propertyNameId);
+ }
}
templateSize += size;
}
Index: src/main/java/org/apache/jackrabbit/oak/plugins/segment/Segment.java
===================================================================
--- src/main/java/org/apache/jackrabbit/oak/plugins/segment/Segment.java (revision 1660580)
+++ src/main/java/org/apache/jackrabbit/oak/plugins/segment/Segment.java (working copy)
@@ -54,10 +54,11 @@
/**
* Version of the segment storage format.
*
- * - 10 = all Oak versions released so far
+ * - 10 = all Oak versions previous to 11
+ * - 11 = all Oak versions starting from TODO
*
*/
- public static final byte STORAGE_FORMAT_VERSION = 10;
+ public static final byte STORAGE_FORMAT_VERSION = 11;
/**
* Number of bytes used for storing a record identifier. One byte
@@ -116,6 +117,8 @@
private final ByteBuffer data;
+ private final byte segmentFormat;
+
/**
* Referenced segment identifiers. Entries are initialized lazily in
* {@link #getRefId(int)}. Set to {@code null} for bulk segments.
@@ -142,13 +145,16 @@
this.data = checkNotNull(data);
if (id.isDataSegmentId()) {
+ segmentFormat = data.get(3);
checkState(data.get(0) == '0'
&& data.get(1) == 'a'
&& data.get(2) == 'K'
- && data.get(3) == STORAGE_FORMAT_VERSION);
+ && (segmentFormat == STORAGE_FORMAT_VERSION - 1 // backward compatible with previous format
+ || segmentFormat == STORAGE_FORMAT_VERSION));
this.refids = new SegmentId[getRefCount()];
refids[0] = id;
} else {
+ this.segmentFormat = STORAGE_FORMAT_VERSION;
this.refids = null;
}
}
@@ -159,6 +165,7 @@
this.data = ByteBuffer.wrap(checkNotNull(buffer));
this.refids = new SegmentId[SEGMENT_REFERENCE_LIMIT + 1];
+ this.segmentFormat = STORAGE_FORMAT_VERSION;
refids[0] = id;
}
@@ -171,6 +178,10 @@
return accessed != 0;
}
+ byte getStorageFormatVersion() {
+ return segmentFormat;
+ }
+
/**
* Maps the given record offset to the respective position within the
* internal {@link #data} array. The validity of a record with the given
@@ -436,19 +447,41 @@
offset += Segment.RECORD_ID_BYTES;
}
- PropertyTemplate[] properties =
- new PropertyTemplate[propertyCount];
- for (int i = 0; i < properties.length; i++) {
+ PropertyTemplate[] properties;
+ if (segmentFormat == STORAGE_FORMAT_VERSION) {
+ properties = readPropsV11(propertyCount, offset);
+ } else {
+ properties = readPropsV10(propertyCount, offset);
+ }
+ return new Template(primaryType, mixinTypes, properties, childName);
+ }
+
+ private PropertyTemplate[] readPropsV10(int propertyCount, int offset) {
+ PropertyTemplate[] properties = new PropertyTemplate[propertyCount];
+ for (int i = 0; i < propertyCount; i++) {
RecordId propertyNameId = readRecordId(offset);
offset += Segment.RECORD_ID_BYTES;
byte type = readByte(offset++);
- properties[i] = new PropertyTemplate(
- i, readString(propertyNameId),
+ properties[i] = new PropertyTemplate(i, readString(propertyNameId),
Type.fromTag(Math.abs(type), type < 0));
}
+ return properties;
+ }
- return new Template(
- primaryType, mixinTypes, properties, childName);
+ private PropertyTemplate[] readPropsV11(int propertyCount, int offset) {
+ PropertyTemplate[] properties = new PropertyTemplate[propertyCount];
+ if (propertyCount > 0) {
+ RecordId id = readRecordId(offset);
+ ListRecord propertyNames = new ListRecord(id, properties.length);
+ offset += Segment.RECORD_ID_BYTES;
+ for (int i = 0; i < propertyCount; i++) {
+ byte type = readByte(offset++);
+ properties[i] = new PropertyTemplate(i,
+ readString(propertyNames.getEntry(i)), Type.fromTag(
+ Math.abs(type), type < 0));
+ }
+ }
+ return properties;
}
long readLength(RecordId id) {
Index: src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeState.java
===================================================================
--- src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeState.java (revision 1660580)
+++ src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeState.java (working copy)
@@ -134,17 +134,39 @@
template.getPropertyTemplate(name);
if (propertyTemplate != null) {
Segment segment = getSegment();
- int ids = 1 + propertyTemplate.getIndex();
- if (template.getChildName() != Template.ZERO_CHILD_NODES) {
- ids++;
+ RecordId id;
+ if (getSegment().getStorageFormatVersion() == Segment.STORAGE_FORMAT_VERSION) {
+ id = getRecordIdV11(segment, template, propertyTemplate);
+ } else {
+ id = getRecordIdV10(segment, template, propertyTemplate);
}
- return new SegmentPropertyState(
- segment.readRecordId(getOffset(0, ids)), propertyTemplate);
+ return new SegmentPropertyState(id, propertyTemplate);
} else {
return null;
}
}
+ private RecordId getRecordIdV10(Segment segment, Template template,
+ PropertyTemplate propertyTemplate) {
+ int ids = 1 + propertyTemplate.getIndex();
+ if (template.getChildName() != Template.ZERO_CHILD_NODES) {
+ ids++;
+ }
+ return segment.readRecordId(getOffset(0, ids));
+ }
+
+ private RecordId getRecordIdV11(Segment segment, Template template,
+ PropertyTemplate propertyTemplate) {
+ int ids = 1;
+ if (template.getChildName() != Template.ZERO_CHILD_NODES) {
+ ids++;
+ }
+ RecordId rid = segment.readRecordId(getOffset(0, ids));
+ ListRecord pIds = new ListRecord(rid,
+ template.getPropertyTemplates().length);
+ return pIds.getEntry(propertyTemplate.getIndex());
+ }
+
@Override @Nonnull
public Iterable getProperties() {
Template template = getTemplate();
@@ -167,10 +189,26 @@
if (template.getChildName() != Template.ZERO_CHILD_NODES) {
ids++;
}
- for (int i = 0; i < propertyTemplates.length; i++) {
- RecordId propertyId = segment.readRecordId(getOffset(0, ids++));
- list.add(new SegmentPropertyState(
- propertyId, propertyTemplates[i]));
+
+ if (segment.getStorageFormatVersion() == Segment.STORAGE_FORMAT_VERSION) {
+ // -- V11 --
+ if (propertyTemplates.length > 0) {
+ ListRecord pIds = new ListRecord(
+ segment.readRecordId(getOffset(0, ids)),
+ propertyTemplates.length);
+ for (int i = 0; i < propertyTemplates.length; i++) {
+ RecordId propertyId = pIds.getEntry(i);
+ list.add(new SegmentPropertyState(propertyId,
+ propertyTemplates[i]));
+ }
+ }
+ } else {
+ // -- V10 --
+ for (int i = 0; i < propertyTemplates.length; i++) {
+ RecordId propertyId = segment.readRecordId(getOffset(0, ids++));
+ list.add(new SegmentPropertyState(propertyId,
+ propertyTemplates[i]));
+ }
}
return list;
@@ -247,11 +285,13 @@
}
Segment segment = getSegment();
- int ids = 1 + propertyTemplate.getIndex();
- if (template.getChildName() != Template.ZERO_CHILD_NODES) {
- ids++;
+ RecordId id;
+ if (getSegment().getStorageFormatVersion() == Segment.STORAGE_FORMAT_VERSION) {
+ id = getRecordIdV11(segment, template, propertyTemplate);
+ } else {
+ id = getRecordIdV10(segment, template, propertyTemplate);
}
- return segment.readString(segment.readRecordId(getOffset(0, ids)));
+ return segment.readString(id);
}
/**
@@ -288,12 +328,12 @@
}
Segment segment = getSegment();
- int ids = 1 + propertyTemplate.getIndex();
- if (template.getChildName() != Template.ZERO_CHILD_NODES) {
- ids++;
+ RecordId id;
+ if (getSegment().getStorageFormatVersion() == Segment.STORAGE_FORMAT_VERSION) {
+ id = getRecordIdV11(segment, template, propertyTemplate);
+ } else {
+ id = getRecordIdV10(segment, template, propertyTemplate);
}
-
- RecordId id = segment.readRecordId(getOffset(0, ids));
segment = id.getSegment();
int size = segment.readInt(id.getOffset());
if (size == 0) {
Index: src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentWriter.java
===================================================================
--- src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentWriter.java (revision 1660580)
+++ src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentWriter.java (working copy)
@@ -119,6 +119,7 @@
* avoid storing duplicates of frequently occurring data.
* Should only be accessed from synchronized blocks to prevent corruption.
*/
+ @SuppressWarnings("serial")
private final Map