/** * Gets the sum of the sizes of the blocks in this record, in bytes. * * @return */ public int size() { int result = 0; for (PropertyBlock block : blockRecords) { result += block.getSize(); } return result; }
public void ensureHeavy(PropertyBlock block) { if (block.getType() == PropertyType.STRING) { if (block.isLight()) { Collection<DynamicRecord> stringRecords = stringPropertyStore.getLightRecords(block.getSingleValueLong()); for (DynamicRecord stringRecord : stringRecords) { stringRecord.setType(PropertyType.STRING.intValue()); block.addValueRecord(stringRecord); } } for (DynamicRecord stringRecord : block.getValueRecords()) { stringPropertyStore.ensureHeavy(stringRecord); } } else if (block.getType() == PropertyType.ARRAY) { if (block.isLight()) { Collection<DynamicRecord> arrayRecords = arrayPropertyStore.getLightRecords(block.getSingleValueLong()); for (DynamicRecord arrayRecord : arrayRecords) { arrayRecord.setType(PropertyType.ARRAY.intValue()); block.addValueRecord(arrayRecord); } } for (DynamicRecord arrayRecord : block.getValueRecords()) { arrayPropertyStore.ensureHeavy(arrayRecord); } } }
private void deleteNode2( long node, DefinedProperty prop1, DefinedProperty prop2, DefinedProperty prop3) throws IOException { ArrayMap<Integer, Pair<DefinedProperty, Long>> props = new ArrayMap<>(); xaCon.getTransaction().nodeLoadProperties(node, false, newPropertyReceiver(props)); int count = 0; for (int keyId : props.keySet()) { long id = props.get(keyId).other(); PropertyRecord record = pStore.getRecord(id); PropertyBlock block = record.getPropertyBlock(props.get(keyId).first().propertyKeyId()); DefinedProperty data = block.newPropertyData(pStore); if (data.propertyKeyId() == prop1.propertyKeyId()) { assertEquals("prop1", MyPropertyKeyToken.getIndexFor(keyId).name()); assertEquals("-string2", data.value()); } else if (data.propertyKeyId() == prop2.propertyKeyId()) { assertEquals("prop2", MyPropertyKeyToken.getIndexFor(keyId).name()); assertEquals(-2, data.value()); } else if (data.propertyKeyId() == prop3.propertyKeyId()) { assertEquals("prop3", MyPropertyKeyToken.getIndexFor(keyId).name()); assertEquals(true, data.value()); xaCon.getTransaction().nodeRemoveProperty(node, prop3.propertyKeyId()); } else { throw new IOException(); } count++; } assertEquals(3, count); CountingPropertyReceiver propertyCounter = new CountingPropertyReceiver(); xaCon.getTransaction().nodeLoadProperties(node, false, propertyCounter); assertEquals(3, propertyCounter.count); MutableRelationshipLoadingPosition pos = getPosition(xaCon, node); Iterator<RelationshipRecord> rels = getMore(xaCon, node, pos).iterator(); assertTrue(rels.hasNext()); xaCon.getTransaction().nodeDelete(node); }
public PropertyBlock getPropertyBlock(int keyIndex) { for (PropertyBlock block : blockRecords) { if (block.getKeyIndexId() == keyIndex) { return block; } } return null; }
private void updateRecord(PropertyRecord record, PersistenceWindow window) { long id = record.getId(); registerIdFromUpdateRecord(id); Buffer buffer = window.getOffsettedBuffer(id); if (record.inUse()) { // Set up the record header short prevModifier = record.getPrevProp() == Record.NO_NEXT_RELATIONSHIP.intValue() ? 0 : (short) ((record.getPrevProp() & 0xF00000000L) >> 28); short nextModifier = record.getNextProp() == Record.NO_NEXT_RELATIONSHIP.intValue() ? 0 : (short) ((record.getNextProp() & 0xF00000000L) >> 32); byte modifiers = (byte) (prevModifier | nextModifier); /* * [pppp,nnnn] previous, next high bits */ buffer.put(modifiers); buffer.putInt((int) record.getPrevProp()).putInt((int) record.getNextProp()); // Then go through the blocks int longsAppended = 0; // For marking the end of blocks for (PropertyBlock block : record.getPropertyBlocks()) { long[] propBlockValues = block.getValueBlocks(); for (long propBlockValue : propBlockValues) { buffer.putLong(propBlockValue); } longsAppended += propBlockValues.length; /* * For each block we need to update its dynamic record chain if * it is just created. Deleted dynamic records are in the property * record and dynamic records are never modified. Also, they are * assigned as a whole, so just checking the first should be enough. */ if (!block.isLight() && block.getValueRecords().get(0).isCreated()) { updateDynamicRecords(block.getValueRecords()); } } if (longsAppended < PropertyType.getPayloadSizeLongs()) { buffer.putLong(0); } } else { if (!isInRecoveryMode()) { freeId(id); } // skip over the record header, nothing useful there buffer.setOffset(buffer.getOffset() + 9); buffer.putLong(0); } updateDynamicRecords(record.getDeletedRecords()); }
public void addPropertyBlock(PropertyBlock block) { assert size() + block.getSize() <= PropertyType.getPayloadSize() : ("Exceeded capacity of property record " + this + ". My current size is reported as " + size() + "The added block was " + block + " (note that size is " + block.getSize() + ")"); blockRecords.add(block); }
private void deleteRel1( long rel, DefinedProperty prop1, DefinedProperty prop2, DefinedProperty prop3, long firstNode, long secondNode, int relType) throws IOException { ArrayMap<Integer, Pair<DefinedProperty, Long>> props = new ArrayMap<>(); xaCon.getTransaction().relLoadProperties(rel, false, newPropertyReceiver(props)); int count = 0; for (int keyId : props.keySet()) { long id = props.get(keyId).other(); PropertyRecord record = pStore.getRecord(id); PropertyBlock block = record.getPropertyBlock(props.get(keyId).first().propertyKeyId()); DefinedProperty data = block.newPropertyData(pStore); if (data.propertyKeyId() == prop1.propertyKeyId()) { assertEquals("prop1", MyPropertyKeyToken.getIndexFor(keyId).name()); assertEquals("-string1", data.value()); } else if (data.propertyKeyId() == prop2.propertyKeyId()) { assertEquals("prop2", MyPropertyKeyToken.getIndexFor(keyId).name()); assertEquals(-1, data.value()); } else if (data.propertyKeyId() == prop3.propertyKeyId()) { assertEquals("prop3", MyPropertyKeyToken.getIndexFor(keyId).name()); assertEquals(false, data.value()); xaCon.getTransaction().relRemoveProperty(rel, prop3.propertyKeyId()); } else { throw new IOException(); } count++; } assertEquals(3, count); CountingPropertyReceiver propertyCounter = new CountingPropertyReceiver(); xaCon.getTransaction().relLoadProperties(rel, false, propertyCounter); assertEquals(3, propertyCounter.count); RelationshipRecord relData = xaCon.getTransaction().relLoadLight(rel); assertEquals(firstNode, relData.getFirstNode()); assertEquals(secondNode, relData.getSecondNode()); assertEquals(relType, relData.getType()); xaCon.getTransaction().relDelete(rel); MutableRelationshipLoadingPosition firstPos = getPosition(xaCon, firstNode); Iterator<RelationshipRecord> first = getMore(xaCon, firstNode, firstPos).iterator(); first.next(); MutableRelationshipLoadingPosition secondPos = getPosition(xaCon, secondNode); Iterator<RelationshipRecord> second = getMore(xaCon, secondNode, secondPos).iterator(); second.next(); assertTrue(first.hasNext()); assertTrue(second.hasNext()); }
public static boolean encode( int keyId, Object array, PropertyBlock target, int payloadSizeInBytes) { /* * If the array is huge, we don't have to check anything else. * So do the length check first. */ int arrayLength = Array.getLength(array); if (arrayLength > 63) /*because we only use 6 bits for length*/ { return false; } ShortArray type = typeOf(array); if (type == null) { return false; } int requiredBits = type.calculateRequiredBitsForArray(array, arrayLength); if (!willFit(requiredBits, arrayLength, payloadSizeInBytes)) { // Too big array return false; } final int numberOfBytes = calculateNumberOfBlocksUsed(arrayLength, requiredBits) * 8; if (Bits.requiredLongs(numberOfBytes) > PropertyType.getPayloadSizeLongs()) { return false; } Bits result = Bits.bits(numberOfBytes); // [][][ ,bbbb][bbll,llll][yyyy,tttt][kkkk,kkkk][kkkk,kkkk][kkkk,kkkk] writeHeader(keyId, type, arrayLength, requiredBits, result); type.writeAll(array, arrayLength, requiredBits, result); target.setValueBlocks(result.getLongs()); return true; }
/* * It is assumed that the argument does hold a property block - all zeros is * a valid (not in use) block, so even if the Bits object has been exhausted a * result is returned, that has inUse() return false. Also, the argument is not * touched. */ private PropertyBlock getPropertyBlock(Buffer buffer) { long header = buffer.getLong(); PropertyType type = PropertyType.getPropertyType(header, true); if (type == null) { return null; } PropertyBlock toReturn = new PropertyBlock(); // toReturn.setInUse( true ); int numBlocks = type.calculateNumberOfBlocksUsed(header); long[] blockData = new long[numBlocks]; blockData[0] = header; // we already have that for (int i = 1; i < numBlocks; i++) { blockData[i] = buffer.getLong(); } toReturn.setValueBlocks(blockData); return toReturn; }
public PropertyRecord getRecord(long id) { PropertyRecord record; PersistenceWindow window = acquireWindow(id, OperationType.READ); try { record = getRecord(id, window, RecordLoad.NORMAL); } finally { releaseWindow(window); } for (PropertyBlock block : record.getPropertyBlocks()) { // assert block.inUse(); if (block.getType() == PropertyType.STRING) { Collection<DynamicRecord> stringRecords = stringPropertyStore.getLightRecords(block.getSingleValueLong()); for (DynamicRecord stringRecord : stringRecords) { stringRecord.setType(PropertyType.STRING.intValue()); block.addValueRecord(stringRecord); } } else if (block.getType() == PropertyType.ARRAY) { Collection<DynamicRecord> arrayRecords = arrayPropertyStore.getLightRecords(block.getSingleValueLong()); for (DynamicRecord arrayRecord : arrayRecords) { arrayRecord.setType(PropertyType.ARRAY.intValue()); block.addValueRecord(arrayRecord); } } } return record; }
public static Object decode(PropertyBlock block) { Bits bits = Bits.bitsFromLongs(Arrays.copyOf(block.getValueBlocks(), block.getValueBlocks().length)); // [][][ ,bbbb][bbll,llll][yyyy,tttt][kkkk,kkkk][kkkk,kkkk][kkkk,kkkk] bits.getInt(24); // Get rid of key bits.getByte(4); // Get rid of short array type int typeId = bits.getByte(4); int arrayLength = bits.getByte(6); int requiredBits = bits.getByte(6); /* * So, it can be the case that values require 64 bits to store. However, you cannot encode this * value with 6 bits. calculateRequiredBitsForArray never returns 0, because even for an array of * all 0s one bit is required for every value. So when writing, we let it overflow and write out * 0. When we are reading back, we just have to make sure that reading in 0 means 64. */ if (requiredBits == 0) { requiredBits = 64; } ShortArray type = typeOf((byte) typeId); return type.createArray(arrayLength, bits, requiredBits); }
private void validateRel2( long rel, DefinedProperty prop1, DefinedProperty prop2, DefinedProperty prop3, long firstNode, long secondNode, int relType) throws IOException { ArrayMap<Integer, Pair<DefinedProperty, Long>> props = new ArrayMap<>(); xaCon.getTransaction().relLoadProperties(rel, false, newPropertyReceiver(props)); int count = 0; for (int keyId : props.keySet()) { long id = props.get(keyId).other(); PropertyRecord record = pStore.getRecord(id); PropertyBlock block = record.getPropertyBlock(props.get(keyId).first().propertyKeyId()); DefinedProperty data = block.newPropertyData(pStore); if (data.propertyKeyId() == prop1.propertyKeyId()) { assertEquals("prop1", MyPropertyKeyToken.getIndexFor(keyId).name()); assertEquals("string2", data.value()); xaCon.getTransaction().relChangeProperty(rel, prop1.propertyKeyId(), "-string2"); } else if (data.propertyKeyId() == prop2.propertyKeyId()) { assertEquals("prop2", MyPropertyKeyToken.getIndexFor(keyId).name()); assertEquals(2, data.value()); xaCon.getTransaction().relChangeProperty(rel, prop2.propertyKeyId(), new Integer(-2)); } else if (data.propertyKeyId() == prop3.propertyKeyId()) { assertEquals("prop3", MyPropertyKeyToken.getIndexFor(keyId).name()); assertEquals(false, data.value()); xaCon.getTransaction().relChangeProperty(rel, prop3.propertyKeyId(), true); } else { throw new IOException(); } count++; } assertEquals(3, count); RelationshipRecord relData = xaCon.getTransaction().relLoadLight(rel); assertEquals(firstNode, relData.getFirstNode()); assertEquals(secondNode, relData.getSecondNode()); assertEquals(relType, relData.getType()); }
/* * This will add the value records without checking if they are already * in the block - so make sure to call this after checking isHeavy() or * you will end up with duplicates. */ public void makeHeavy(PropertyBlock record) { if (record.getType() == PropertyType.STRING) { Collection<DynamicRecord> stringRecords = stringPropertyStore.getLightRecords(record.getSingleValueLong()); for (DynamicRecord stringRecord : stringRecords) { stringRecord.setType(PropertyType.STRING.intValue()); record.addValueRecord(stringRecord); } } else if (record.getType() == PropertyType.ARRAY) { Collection<DynamicRecord> arrayRecords = arrayPropertyStore.getLightRecords(record.getSingleValueLong()); for (DynamicRecord arrayRecord : arrayRecords) { arrayRecord.setType(PropertyType.ARRAY.intValue()); record.addValueRecord(arrayRecord); } } }
public void makeHeavyIfLight(PropertyBlock record) { if (record.isLight()) { /* * This will add the value records without checking if they are already * in the block - so we only call this after checking isLight() or * else we will end up with duplicates. */ if (record.getType() == PropertyType.STRING) { Collection<DynamicRecord> stringRecords = stringPropertyStore.getLightRecords(record.getSingleValueLong()); for (DynamicRecord stringRecord : stringRecords) { stringRecord.setType(PropertyType.STRING.intValue()); record.addValueRecord(stringRecord); } } else if (record.getType() == PropertyType.ARRAY) { Collection<DynamicRecord> arrayRecords = arrayPropertyStore.getLightRecords(record.getSingleValueLong()); for (DynamicRecord arrayRecord : arrayRecords) { arrayRecord.setType(PropertyType.ARRAY.intValue()); record.addValueRecord(arrayRecord); } } } }
public static Object getStringFor(AbstractDynamicStore store, PropertyBlock propertyBlock) { return getStringFor(store, propertyBlock.getSingleValueLong(), propertyBlock.getValueRecords()); }
public void encodeValue(PropertyBlock block, int keyId, Object value) { if (value instanceof String) { // Try short string first, i.e. inlined in the property block String string = (String) value; if (LongerShortString.encode(keyId, string, block, PropertyType.getPayloadSize())) return; // Fall back to dynamic string store long stringBlockId = nextStringBlockId(); setSingleBlockValue(block, keyId, PropertyType.STRING, stringBlockId); byte[] encodedString = encodeString(string); Collection<DynamicRecord> valueRecords = allocateStringRecords(stringBlockId, encodedString); for (DynamicRecord valueRecord : valueRecords) { valueRecord.setType(PropertyType.STRING.intValue()); block.addValueRecord(valueRecord); } } else if (value instanceof Integer) setSingleBlockValue(block, keyId, PropertyType.INT, ((Integer) value).longValue()); else if (value instanceof Boolean) setSingleBlockValue( block, keyId, PropertyType.BOOL, (((Boolean) value).booleanValue() ? 1L : 0L)); else if (value instanceof Float) setSingleBlockValue( block, keyId, PropertyType.FLOAT, Float.floatToRawIntBits(((Float) value).floatValue())); else if (value instanceof Long) { long keyAndType = keyId | (((long) PropertyType.LONG.intValue()) << 24); if (ShortArray.LONG.getRequiredBits((Long) value) <= 35) { // We only need one block for this value, special layout compared to, say, an // integer block.setSingleBlock(keyAndType | (1L << 28) | (((Long) value).longValue() << 29)); } else { // We need two blocks for this value block.setValueBlocks(new long[] {keyAndType, ((Long) value).longValue()}); } } else if (value instanceof Double) block.setValueBlocks( new long[] { keyId | (((long) PropertyType.DOUBLE.intValue()) << 24), Double.doubleToRawLongBits(((Double) value).doubleValue()) }); else if (value instanceof Byte) setSingleBlockValue(block, keyId, PropertyType.BYTE, ((Byte) value).longValue()); else if (value instanceof Character) setSingleBlockValue(block, keyId, PropertyType.CHAR, ((Character) value).charValue()); else if (value instanceof Short) setSingleBlockValue(block, keyId, PropertyType.SHORT, ((Short) value).longValue()); else if (value .getClass() .isArray()) { // Try short array first, i.e. inlined in the property block if (ShortArray.encode(keyId, value, block, PropertyType.getPayloadSize())) return; // Fall back to dynamic array store long arrayBlockId = nextArrayBlockId(); setSingleBlockValue(block, keyId, PropertyType.ARRAY, arrayBlockId); Collection<DynamicRecord> arrayRecords = allocateArrayRecords(arrayBlockId, value); for (DynamicRecord valueRecord : arrayRecords) { valueRecord.setType(PropertyType.ARRAY.intValue()); block.addValueRecord(valueRecord); } } else { throw new IllegalArgumentException( "Unknown property type on: " + value + ", " + value.getClass()); } }
public Object getValue(PropertyBlock propertyBlock) { return propertyBlock.getType().getValue(propertyBlock, this); }
public String getStringFor(PropertyBlock propertyBlock) { ensureHeavy(propertyBlock); return getStringFor(propertyBlock.getValueRecords()); }
private void setSingleBlockValue( PropertyBlock block, int keyId, PropertyType type, long longValue) { block.setSingleBlock(keyId | (((long) type.intValue()) << 24) | (longValue << 28)); }
public Object getArrayFor(PropertyBlock propertyBlock) { ensureHeavy(propertyBlock); return getArrayFor(propertyBlock.getValueRecords()); }
public Object getArrayFor(PropertyBlock propertyBlock) { assert !propertyBlock.isLight(); return getArrayFor( propertyBlock.getSingleValueLong(), propertyBlock.getValueRecords(), arrayPropertyStore); }
private void validateNodeRel2( long node, DefinedProperty prop1, DefinedProperty prop2, DefinedProperty prop3, long rel1, long rel2, int relType1, int relType2) throws IOException { NodeRecord nodeRecord = xaCon.getTransaction().nodeLoadLight(node); assertTrue(nodeRecord != null); ArrayMap<Integer, Pair<DefinedProperty, Long>> props = new ArrayMap<>(); xaCon.getTransaction().nodeLoadProperties(node, false, newPropertyReceiver(props)); int count = 0; for (int keyId : props.keySet()) { long id = props.get(keyId).other(); PropertyRecord record = pStore.getRecord(id); PropertyBlock block = record.getPropertyBlock(props.get(keyId).first().propertyKeyId()); DefinedProperty data = block.newPropertyData(pStore); if (data.propertyKeyId() == prop1.propertyKeyId()) { assertEquals("prop1", MyPropertyKeyToken.getIndexFor(keyId).name()); assertEquals("string2", data.value()); xaCon.getTransaction().nodeChangeProperty(node, prop1.propertyKeyId(), "-string2"); } else if (data.propertyKeyId() == prop2.propertyKeyId()) { assertEquals("prop2", MyPropertyKeyToken.getIndexFor(keyId).name()); assertEquals(2, data.value()); xaCon.getTransaction().nodeChangeProperty(node, prop2.propertyKeyId(), new Integer(-2)); } else if (data.propertyKeyId() == prop3.propertyKeyId()) { assertEquals("prop3", MyPropertyKeyToken.getIndexFor(keyId).name()); assertEquals(false, data.value()); xaCon.getTransaction().nodeChangeProperty(node, prop3.propertyKeyId(), true); } else { throw new IOException(); } count++; } assertEquals(3, count); count = 0; MutableRelationshipLoadingPosition pos = getPosition(xaCon, node); while (true) { Iterable<RelationshipRecord> relData = getMore(xaCon, node, pos); if (!relData.iterator().hasNext()) { break; } for (RelationshipRecord rel : relData) { if (rel.getId() == rel1) { assertEquals(node, rel.getSecondNode()); assertEquals(relType1, rel.getType()); } else if (rel.getId() == rel2) { assertEquals(node, rel.getFirstNode()); assertEquals(relType2, rel.getType()); } else { throw new IOException(); } count++; } } assertEquals(2, count); }