use of org.neo4j.kernel.impl.store.record.PropertyBlock in project neo4j by neo4j.
the class PropertyCreator method primitiveSetProperty.
public <P extends PrimitiveRecord> void primitiveSetProperty(RecordProxy<Long, P, Void> primitiveRecordChange, int propertyKey, Object value, RecordAccess<Long, PropertyRecord, PrimitiveRecord> propertyRecords) {
PropertyBlock block = encodePropertyValue(propertyKey, value);
P primitive = primitiveRecordChange.forReadingLinkage();
assert traverser.assertPropertyChain(primitive, propertyRecords);
int newBlockSizeInBytes = block.getSize();
// Traverse the existing property chain. Tracking two things along the way:
// - (a) Free space for this block (candidateHost)
// - (b) Existence of a block with the property key
// Chain traversal can be aborted only if:
// - (1) (b) occurs and new property block fits where the current is
// - (2) (a) occurs and (b) has occurred, but new property block didn't fit
// - (3) (b) occurs and (a) has occurred
// - (4) Chain ends
RecordProxy<Long, PropertyRecord, PrimitiveRecord> freeHostProxy = null;
RecordProxy<Long, PropertyRecord, PrimitiveRecord> existingHostProxy = null;
long prop = primitive.getNextProp();
while (// <-- (4)
prop != Record.NO_NEXT_PROPERTY.intValue()) {
RecordProxy<Long, PropertyRecord, PrimitiveRecord> proxy = propertyRecords.getOrLoad(prop, primitive);
PropertyRecord propRecord = proxy.forReadingLinkage();
assert propRecord.inUse() : propRecord;
// (a) search for free space
if (propertyFitsInside(newBlockSizeInBytes, propRecord)) {
freeHostProxy = proxy;
if (existingHostProxy != null) {
// (2)
PropertyRecord freeHost = proxy.forChangingData();
freeHost.addPropertyBlock(block);
freeHost.setChanged(primitive);
assert traverser.assertPropertyChain(primitive, propertyRecords);
return;
}
}
// (b) search for existence of property key
PropertyBlock existingBlock = propRecord.getPropertyBlock(propertyKey);
if (existingBlock != null) {
// We found an existing property and whatever happens we have to remove the existing
// block so that we can add the new one, where ever we decide to place it
existingHostProxy = proxy;
PropertyRecord existingHost = existingHostProxy.forChangingData();
removeProperty(primitive, existingHost, existingBlock);
// Now see if we at this point can add the new block
if (// cheap check
newBlockSizeInBytes <= existingBlock.getSize() || // fallback check
propertyFitsInside(newBlockSizeInBytes, existingHost)) {
// (1) yes we could add it right into the host of the existing block
existingHost.addPropertyBlock(block);
assert traverser.assertPropertyChain(primitive, propertyRecords);
return;
} else if (freeHostProxy != null) {
// (3) yes we could add it to a previously found host with sufficiently free space in it
PropertyRecord freeHost = freeHostProxy.forChangingData();
freeHost.addPropertyBlock(block);
freeHost.setChanged(primitive);
assert traverser.assertPropertyChain(primitive, propertyRecords);
return;
}
// else we can't add it at this point
}
// Continue down the chain
prop = propRecord.getNextProp();
}
// At this point we haven't added the property block, although we may have found room for it
// along the way. If we didn't then just create a new record, it's fine
PropertyRecord freeHost = null;
if (freeHostProxy == null) {
// We couldn't find free space along the way, so create a new host record
freeHost = propertyRecords.create(propertyRecordIdGenerator.nextId(), primitive).forChangingData();
freeHost.setInUse(true);
if (primitive.getNextProp() != Record.NO_NEXT_PROPERTY.intValue()) {
// This isn't the first property record for the entity, re-shuffle the first one so that
// the new one becomes the first
PropertyRecord prevProp = propertyRecords.getOrLoad(primitive.getNextProp(), primitive).forChangingLinkage();
assert prevProp.getPrevProp() == Record.NO_PREVIOUS_PROPERTY.intValue();
prevProp.setPrevProp(freeHost.getId());
freeHost.setNextProp(prevProp.getId());
prevProp.setChanged(primitive);
}
// By the way, this is the only condition where the primitive record also needs to change
primitiveRecordChange.forChangingLinkage().setNextProp(freeHost.getId());
} else {
freeHost = freeHostProxy.forChangingData();
}
// At this point we know that we have a host record with sufficient space in it for the block
// to add, so simply add it
freeHost.addPropertyBlock(block);
assert traverser.assertPropertyChain(primitive, propertyRecords);
}
use of org.neo4j.kernel.impl.store.record.PropertyBlock in project neo4j by neo4j.
the class PhysicalLogCommandReaderV2_2 method readPropertyBlock.
private PropertyBlock readPropertyBlock(ReadableChannel channel) throws IOException {
PropertyBlock toReturn = new PropertyBlock();
// the size is stored in bytes // 1
byte blockSize = channel.get();
assert blockSize > 0 && blockSize % 8 == 0 : blockSize + " is not a valid block size value";
// Read in blocks
long[] blocks = readLongs(channel, blockSize / 8);
assert blocks.length == blockSize / 8 : blocks.length + " longs were read in while i asked for what corresponds to " + blockSize;
assert PropertyType.getPropertyTypeOrThrow(blocks[0]).calculateNumberOfBlocksUsed(blocks[0]) == blocks.length : blocks.length + " is not a valid number of blocks for type " + PropertyType.getPropertyTypeOrThrow(blocks[0]);
/*
* Ok, now we may be ready to return, if there are no DynamicRecords. So
* we start building the Object
*/
toReturn.setValueBlocks(blocks);
/*
* Read in existence of DynamicRecords. Remember, this has already been
* read in the buffer with the blocks, above.
*/
if (readDynamicRecords(channel, toReturn, PROPERTY_BLOCK_DYNAMIC_RECORD_ADDER) == -1) {
return null;
}
return toReturn;
}
use of org.neo4j.kernel.impl.store.record.PropertyBlock in project neo4j by neo4j.
the class PhysicalLogCommandReaderV3_0 method readPropertyRecord.
private PropertyRecord readPropertyRecord(long id, ReadableChannel channel) throws IOException {
// in_use(byte)+type(int)+key_indexId(int)+prop_blockId(long)+
// prev_prop_id(long)+next_prop_id(long)
PropertyRecord record = new PropertyRecord(id);
// 1
byte flags = channel.get();
boolean inUse = bitFlag(flags, Record.IN_USE.byteValue());
boolean nodeProperty = !bitFlag(flags, Record.REL_PROPERTY.byteValue());
boolean requireSecondaryUnit = bitFlag(flags, Record.REQUIRE_SECONDARY_UNIT);
boolean hasSecondaryUnit = bitFlag(flags, Record.HAS_SECONDARY_UNIT);
record.setRequiresSecondaryUnit(requireSecondaryUnit);
// 8
long nextProp = channel.getLong();
// 8
long prevProp = channel.getLong();
record.setNextProp(nextProp);
record.setPrevProp(prevProp);
// 8
long primitiveId = channel.getLong();
if (primitiveId != -1 && nodeProperty) {
record.setNodeId(primitiveId);
} else if (primitiveId != -1) {
record.setRelId(primitiveId);
}
if (hasSecondaryUnit) {
record.setSecondaryUnitId(channel.getLong());
}
int nrPropBlocks = channel.get();
assert nrPropBlocks >= 0;
if (nrPropBlocks > 0) {
record.setInUse(true);
}
while (nrPropBlocks-- > 0) {
PropertyBlock block = readPropertyBlock(channel);
if (block == null) {
return null;
}
record.addPropertyBlock(block);
}
int deletedRecords = readDynamicRecords(channel, record, PROPERTY_DELETED_DYNAMIC_RECORD_ADDER);
if (deletedRecords == -1) {
return null;
}
assert deletedRecords >= 0;
while (deletedRecords-- > 0) {
DynamicRecord read = readDynamicRecord(channel);
if (read == null) {
return null;
}
record.addDeletedRecord(read);
}
if ((inUse && !record.inUse()) || (!inUse && record.inUse())) {
throw new IllegalStateException("Weird, inUse was read in as " + inUse + " but the record is " + record);
}
return record;
}
use of org.neo4j.kernel.impl.store.record.PropertyBlock in project neo4j by neo4j.
the class EntityStoreUpdaterStep method reassignDynamicRecordIds.
static void reassignDynamicRecordIds(PropertyStore propertyStore, PropertyBlock[] blocks, int offset, int length) {
// where we know we have a single thread doing this.
for (int i = 0; i < length; i++) {
PropertyBlock block = blocks[offset + i];
PropertyType type = block.getType();
switch(type) {
case STRING:
reassignDynamicRecordIds(block, type, propertyStore.getStringStore());
break;
case ARRAY:
reassignDynamicRecordIds(block, type, propertyStore.getArrayStore());
break;
// No need to do anything be default, we only need to relink for dynamic records
default:
}
}
}
use of org.neo4j.kernel.impl.store.record.PropertyBlock in project neo4j by neo4j.
the class PropertyEncoderStep method process.
@Override
protected void process(Batch<INPUT, RECORD> batch, BatchSender sender) {
RelativeIdRecordAllocator stringAllocator = new RelativeIdRecordAllocator(stringDataSize);
RelativeIdRecordAllocator arrayAllocator = new RelativeIdRecordAllocator(arrayDataSize);
PropertyCreator propertyCreator = new PropertyCreator(stringAllocator, arrayAllocator, null, null);
int blockCountGuess = (int) averageBlocksPerBatch.average();
PropertyBlock[] propertyBlocks = new PropertyBlock[blockCountGuess == 0 ? batch.input.length : blockCountGuess + batch.input.length / 20];
int blockCursor = 0;
int[] lengths = new int[batch.input.length];
for (int i = 0; i < batch.input.length; i++) {
stringAllocator.initialize();
arrayAllocator.initialize();
INPUT input = batch.input[i];
if (!input.hasFirstPropertyId()) {
// Encode the properties and attach the blocks to the BatchEntity.
// Dynamic records for each entity will start from 0, they will be reassigned later anyway
int count = input.properties().length >> 1;
if (blockCursor + count > propertyBlocks.length) {
propertyBlocks = copyOf(propertyBlocks, max(propertyBlocks.length << 1, blockCursor + count));
}
propertyKeyHolder.propertyKeysAndValues(propertyBlocks, blockCursor, input.properties(), propertyCreator);
lengths[i] = count;
blockCursor += count;
}
}
batch.propertyBlocks = propertyBlocks;
batch.propertyBlocksLengths = lengths;
averageBlocksPerBatch.add(blockCursor);
sender.send(batch);
}
Aggregations