Index: src/main/java/org/apache/jackrabbit/oak/plugins/segment/Segment.java =================================================================== --- src/main/java/org/apache/jackrabbit/oak/plugins/segment/Segment.java (revision 1659233) +++ src/main/java/org/apache/jackrabbit/oak/plugins/segment/Segment.java (working copy) @@ -184,7 +184,12 @@ } int getRefCount() { - return (data.get(REF_COUNT_OFFSET) & 0xff) + 1; + int refcount = (data.get(REF_COUNT_OFFSET) & 0xff); + if (refcount > SEGMENT_REFERENCE_LIMIT) { + throw new SegmentOverflowException( + "Segment cannot have more than 255 references " + id); + } + return refcount + 1; } public int getRootCount() { @@ -428,19 +433,41 @@ offset += Segment.RECORD_ID_BYTES; } - PropertyTemplate[] properties = - new PropertyTemplate[propertyCount]; - for (int i = 0; i < properties.length; i++) { + PropertyTemplate[] properties; + if (SegmentWriter.V1TPL_R) { + properties = readPropsV1(propertyCount, offset); + } else { + properties = readPropsV0(propertyCount, offset); + } + return new Template(primaryType, mixinTypes, properties, childName); + } + + private PropertyTemplate[] readPropsV0(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[] readPropsV1(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 1659233) +++ src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeState.java (working copy) @@ -130,21 +130,47 @@ return property; } - PropertyTemplate propertyTemplate = - template.getPropertyTemplate(name); + PropertyTemplate propertyTemplate = template.getPropertyTemplate(name); if (propertyTemplate != null) { - Segment segment = getSegment(); - int ids = 1 + propertyTemplate.getIndex(); - if (template.getChildName() != Template.ZERO_CHILD_NODES) { - ids++; + // TODO + if (SegmentWriter.V1) { + return readPropV1(template, propertyTemplate); + } else { + return readPropV0(template, propertyTemplate); } - return new SegmentPropertyState( - segment.readRecordId(getOffset(0, ids)), propertyTemplate); } else { return null; } } + private SegmentPropertyState readPropV0(Template template, PropertyTemplate propertyTemplate) { + Segment segment = getSegment(); + int ids = 1 + propertyTemplate.getIndex(); + if (template.getChildName() != Template.ZERO_CHILD_NODES) { + ids++; + } + RecordId rid = segment.readRecordId(getOffset(0, ids)); + SegmentPropertyState sps = new SegmentPropertyState(rid, propertyTemplate); + return sps; + } + + private SegmentPropertyState readPropV1(Template template, PropertyTemplate propertyTemplate) { + Segment segment = getSegment(); + 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); + RecordId pid = pIds.getEntry(propertyTemplate.getIndex()); + + SegmentPropertyState sps = new SegmentPropertyState(pid, + propertyTemplate); + return sps; + } + @Override @Nonnull public Iterable getProperties() { Template template = getTemplate(); @@ -167,10 +193,27 @@ 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])); + + //TODO + if (SegmentWriter.V1) { + // -- V1 -- + 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 { + // -- V0 -- + for (int i = 0; i < propertyTemplates.length; i++) { + RecordId propertyId = segment.readRecordId(getOffset(0, ids++)); + list.add(new SegmentPropertyState(propertyId, + propertyTemplates[i])); + } } return list; @@ -246,6 +289,8 @@ return null; } + //TODO update to latest version + System.err.println("#getValueAsString " + name); Segment segment = getSegment(); int ids = 1 + propertyTemplate.getIndex(); if (template.getChildName() != Template.ZERO_CHILD_NODES) { @@ -287,6 +332,8 @@ return emptyList(); } + //TODO update to latest version + System.err.println("#getValuesAsString " + name); Segment segment = getSegment(); int ids = 1 + propertyTemplate.getIndex(); if (template.getChildName() != Template.ZERO_CHILD_NODES) { Index: src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentWriter.java =================================================================== --- src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentWriter.java (revision 1659233) +++ src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentWriter.java (working copy) @@ -83,6 +83,12 @@ */ public class SegmentWriter { + public static boolean V1TPL_W = true; + public static boolean V1TPL_R = true; + + + public static boolean V1 = true; + /** Logger instance */ private static final Logger log = LoggerFactory.getLogger(SegmentWriter.class); @@ -118,6 +124,7 @@ * avoid storing duplicates of frequently occurring data. * Should only be accessed from synchronized blocks to prevent corruption. */ + @SuppressWarnings("serial") private final Map records = new LinkedHashMap(15000, 0.75f, true) { @Override @@ -967,7 +974,18 @@ propertyTypes[i] = (byte) type.tag(); } } - ids.addAll(Arrays.asList(propertyNames)); + + // TODO + RecordId propNamesId = null; + if (V1TPL_W) { + if (propertyNames.length > 0) { + propNamesId = writeList(Arrays.asList(propertyNames)); + ids.add(propNamesId); + } + } else { + ids.addAll(Arrays.asList(propertyNames)); + } + checkState(propertyNames.length < (1 << 18)); head |= propertyNames.length; @@ -984,8 +1002,15 @@ if (childNameId != null) { writeRecordId(childNameId); } + if (V1TPL_W) { + if (propNamesId != null) { + writeRecordId(propNamesId); + } + } for (int i = 0; i < propertyNames.length; i++) { - writeRecordId(propertyNames[i]); + if (!V1TPL_W) { + writeRecordId(propertyNames[i]); + } buffer[position++] = propertyTypes[i]; } @@ -1086,36 +1111,47 @@ ids.add(writeNode(state.getChildNode(template.getChildName())).getRecordId()); } + List pIds = Lists.newArrayList(); for (PropertyTemplate pt : template.getPropertyTemplates()) { String name = pt.getName(); PropertyState property = state.getProperty(name); if (property instanceof SegmentPropertyState && store.containsSegment(((SegmentPropertyState) property).getRecordId().getSegmentId())) { - ids.add(((SegmentPropertyState) property).getRecordId()); + pIds.add(((SegmentPropertyState) property).getRecordId()); } else if (before == null || !store.containsSegment(before.getRecordId().getSegmentId())) { - ids.add(writeProperty(property)); + pIds.add(writeProperty(property)); } else { // reuse previously stored property, if possible PropertyTemplate bt = beforeTemplate.getPropertyTemplate(name); if (bt == null) { - ids.add(writeProperty(property)); // new property + RecordId p = writeProperty(property); + pIds.add(p); // new property } else { SegmentPropertyState bp = beforeTemplate.getProperty( before.getRecordId(), bt.getIndex()); if (property.equals(bp)) { - ids.add(bp.getRecordId()); // no changes + pIds.add(bp.getRecordId()); // no changes } else if (bp.isArray() && bp.getType() != BINARIES) { // reuse entries from the previous list - ids.add(writeProperty(property, bp.getValueRecords())); + pIds.add(writeProperty(property, bp.getValueRecords())); } else { - ids.add(writeProperty(property)); + pIds.add(writeProperty(property)); } } } } + if (!pIds.isEmpty()) { + //TODO + if (V1) { + ids.add(writeList(pIds)); + } else { + ids.addAll(pIds); + } + } + synchronized (this) { RecordId recordId = prepare(RecordType.NODE, 0, ids); for (RecordId id : ids) { Index: src/main/java/org/apache/jackrabbit/oak/plugins/segment/Template.java =================================================================== --- src/main/java/org/apache/jackrabbit/oak/plugins/segment/Template.java (revision 1659233) +++ src/main/java/org/apache/jackrabbit/oak/plugins/segment/Template.java (working copy) @@ -173,9 +173,18 @@ if (childName != ZERO_CHILD_NODES) { offset += RECORD_ID_BYTES; } - offset += index * RECORD_ID_BYTES; - return new SegmentPropertyState( - segment.readRecordId(offset), properties[index]); + + RecordId rid = null; + if (SegmentWriter.V1) { + RecordId lid = segment.readRecordId(offset); + ListRecord props = new ListRecord(lid, properties.length); + + rid = props.getEntry(index); + } else { + offset += index * RECORD_ID_BYTES; + rid = segment.readRecordId(offset); + } + return new SegmentPropertyState(rid, properties[index]); } MapRecord getChildNodeMap(RecordId recordId) { Index: src/test/java/org/apache/jackrabbit/oak/plugins/segment/file/SegmentReferenceLimitTestIT.java =================================================================== --- src/test/java/org/apache/jackrabbit/oak/plugins/segment/file/SegmentReferenceLimitTestIT.java (revision 1659233) +++ src/test/java/org/apache/jackrabbit/oak/plugins/segment/file/SegmentReferenceLimitTestIT.java (working copy) @@ -108,9 +108,14 @@ @Override public Void call() throws Exception { for (int k = 0; ; k++) { - NodeBuilder root = nodeStore.getRoot().builder(); - root.getChildNode("test").setProperty(name + ' ' + k, name + " value " + k); - nodeStore.merge(root, EmptyHook.INSTANCE, CommitInfo.EMPTY); + try { + NodeBuilder root = nodeStore.getRoot().builder(); + root.getChildNode("test").setProperty(name + ' ' + k, name + " value " + k); + nodeStore.merge(root, EmptyHook.INSTANCE, CommitInfo.EMPTY); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } } } }