public static long[] encodeLocalDateTime( int keyId, long epochSecond, long nanoOfSecond ) { int idBits = StandardFormatSettings.PROPERTY_TOKEN_MAXIMUM_ID_BITS; long keyAndType = keyId | (((long) (PropertyType.TEMPORAL.intValue()) << idBits)); long temporalTypeBits = TemporalType.TEMPORAL_LOCAL_DATE_TIME.temporalType << (idBits + 4); long[] data = new long[BLOCKS_LOCAL_DATETIME]; // nanoOfSecond will never require more than 30 bits data[0] = keyAndType | temporalTypeBits | (nanoOfSecond << 32); data[1] = epochSecond; return data; }
private boolean propertyFitsInside( int newBlockSizeInBytes, PropertyRecord propRecord ) { int propSize = propRecord.size(); assert propSize >= 0 : propRecord; return propSize + newBlockSizeInBytes <= PropertyType.getPayloadSize(); }
private Value valueOf( PropertyBlock block ) { if ( block == null ) { return null; } return block.getType().value( block, propertyStore ); } }
/** * Reads blocks[] and constructs {@link PropertyBlock} instances from them, making that abstraction * available to the outside. Done the first time any PropertyBlock is needed or manipulated. */ private void ensureBlocksLoaded() { if ( !blocksLoaded ) { assert blockRecordsCursor == 0; // We haven't loaded the blocks yet, please do so now int index = 0; while ( index < blocksCursor ) { PropertyType type = PropertyType.getPropertyTypeOrThrow( blocks[index] ); PropertyBlock block = new PropertyBlock(); int length = type.calculateNumberOfBlocksUsed( blocks[index] ); block.setValueBlocks( Arrays.copyOfRange( blocks, index, index + length ) ); blockRecords[blockRecordsCursor++] = block; index += length; } blocksLoaded = true; } }
/** * For property records there's no "inUse" byte and we need to read the whole record to * see if there are any PropertyBlocks in use in it. */ @Override public boolean isInUse( PageCursor cursor ) { cursor.setOffset( cursor.getOffset() /*skip...*/ + 1/*mod*/ + 4/*prev*/ + 4/*next*/ ); int blocks = PropertyType.getPayloadSizeLongs(); for ( int i = 0; i < blocks; i++ ) { long block = cursor.getLong(); // Since there's no inUse byte we have to check the special case of first block == 0, which will mean that it's deleted if ( i == 0 && block == 0 ) { return false; } if ( PropertyType.getPropertyTypeOrNull( block ) != null ) { return true; } } return false; } }
result.append( type == null ? "<unknown type>" : type.name() ).append( ',' ); result.append( "key=" ).append( valueBlocks == null ? "?" : Integer.toString( getKeyIndexId() ) ); if ( type != null ) break; default: Object value = type.value( this, null ).asObject(); if ( value != null && value.getClass().isArray() )
@Override public void writeString( String value ) throws IllegalArgumentException { // Try short string first, i.e. inlined in the property block if ( LongerShortString.encode( keyId, value, block, PropertyType.getPayloadSize() ) ) { return; } // Fall back to dynamic string store byte[] encodedString = encodeString( value ); List<DynamicRecord> valueRecords = new ArrayList<>(); allocateStringRecords( valueRecords, encodedString, stringAllocator ); setSingleBlockValue( block, keyId, PropertyType.STRING, Iterables.first( valueRecords ).getId() ); for ( DynamicRecord valueRecord : valueRecords ) { valueRecord.setType( PropertyType.STRING.intValue() ); } block.setValueRecords( valueRecords ); }
private static int getMaxSupportedDimensions() { return PropertyType.getPayloadSizeLongs() - 1; }
for ( ; propRecCount <= 3; propRecCount++ ) for ( int i = 1; i <= PropertyType.getPayloadSizeLongs(); i++ ) assertEquals( recordsInUseAtStart + 3, propertyRecordsInUse() ); for ( int i = 1; i <= PropertyType.getPayloadSizeLongs(); i++ ) if ( i == PropertyType.getPayloadSize() - 1 && j != propRecCount - 1 ) else if ( i == PropertyType.getPayloadSize() - 1 && j == propRecCount - 1 ) for ( int i = 1; i <= PropertyType.getPayloadSizeLongs(); i++ ) for ( int i = 1; i <= PropertyType.getPayloadSizeLongs(); i++ )
@Override public byte[] readDynamicRecordHeader( byte[] recordBytes ) { byte itemType = recordBytes[0]; if ( itemType == STRING.byteValue() ) { return headOf( recordBytes, DynamicArrayStore.STRING_HEADER_SIZE ); } else if ( itemType <= DOUBLE.byteValue() ) { return headOf( recordBytes, DynamicArrayStore.NUMBER_HEADER_SIZE ); } else if ( itemType == GEOMETRY.byteValue() ) { return headOf( recordBytes, DynamicArrayStore.GEOMETRY_HEADER_SIZE ); } else if ( itemType == TEMPORAL.byteValue() ) { return headOf( recordBytes, DynamicArrayStore.TEMPORAL_HEADER_SIZE ); } throw new IllegalArgumentException( "Unknown array type " + itemType ); }
PropertyType type = PropertyType.getPropertyTypeOrNull( current ); if ( type == null ) block += type.calculateNumberOfBlocksUsed( current );
public static void encodeValue( PropertyBlock block, int keyId, Value value, DynamicRecordAllocator stringAllocator, DynamicRecordAllocator arrayAllocator, boolean allowStorePointsAndTemporal ) { if ( value instanceof ArrayValue ) { Object asObject = value.asObject(); // Try short array first, i.e. inlined in the property block if ( ShortArray.encode( keyId, asObject, block, PropertyType.getPayloadSize() ) ) { return; } // Fall back to dynamic array store List<DynamicRecord> arrayRecords = new ArrayList<>(); allocateArrayRecords( arrayRecords, asObject, arrayAllocator, allowStorePointsAndTemporal ); setSingleBlockValue( block, keyId, PropertyType.ARRAY, Iterables.first( arrayRecords ).getId() ); for ( DynamicRecord valueRecord : arrayRecords ) { valueRecord.setType( PropertyType.ARRAY.intValue() ); } block.setValueRecords( arrayRecords ); } else { value.writeTo( new PropertyBlockValueWriter( block, keyId, stringAllocator, allowStorePointsAndTemporal ) ); } }
public void setValueBlocks( long[] blocks ) { int expectedPayloadSize = PropertyType.getPayloadSizeLongs(); assert blocks == null || blocks.length <= expectedPayloadSize : "I was given an array of size " + blocks.length + ", but I wanted it to be " + expectedPayloadSize; this.valueBlocks = blocks; if ( valueRecords != null ) { valueRecords.clear(); } }
private PropertyBlock readPropertyBlock( ReadableChannel channel ) throws IOException { PropertyBlock toReturn = new PropertyBlock(); byte blockSize = channel.get(); // the size is stored in bytes // 1 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; }
result.append( type == null ? "<unknown type>" : type.name() ).append( ',' ); result.append( "key=" ).append( valueBlocks == null ? "?" : Integer.toString( getKeyIndexId() ) ); if ( type != null ) break; default: Object value = type.value( this, null ).asObject(); if ( value != null && value.getClass().isArray() )
private static void allocateFromString( Collection<DynamicRecord> target, String[] array, DynamicRecordAllocator recordAllocator ) { byte[][] stringsAsBytes = new byte[array.length][]; int totalBytesRequired = STRING_HEADER_SIZE; // 1b type + 4b array length for ( int i = 0; i < array.length; i++ ) { String string = array[i]; byte[] bytes = PropertyStore.encodeString( string ); stringsAsBytes[i] = bytes; totalBytesRequired += 4/*byte[].length*/ + bytes.length; } ByteBuffer buf = ByteBuffer.allocate( totalBytesRequired ); buf.put( PropertyType.STRING.byteValue() ); buf.putInt( array.length ); for ( byte[] stringAsBytes : stringsAsBytes ) { buf.putInt( stringAsBytes.length ); buf.put( stringAsBytes ); } allocateRecordsFromBytes( target, buf.array(), recordAllocator ); }
PropertyType type = PropertyType.getPropertyTypeOrNull( block ); if ( type == null ) int numberOfBlocksUsed = type.calculateNumberOfBlocksUsed( block ); if ( numberOfBlocksUsed == PropertyType.BLOCKS_USED_FOR_BAD_TYPE_OR_ENCODING )
private void writeArrayHeaderTo( byte[] bytes ) { bytes[0] = (byte) PropertyType.TEMPORAL.intValue(); bytes[1] = (byte) temporalType; }
@Override public void writeString( String value ) throws IllegalArgumentException { // Try short string first, i.e. inlined in the property block if ( LongerShortString.encode( keyId, value, block, PropertyType.getPayloadSize() ) ) { return; } // Fall back to dynamic string store byte[] encodedString = encodeString( value ); List<DynamicRecord> valueRecords = new ArrayList<>(); allocateStringRecords( valueRecords, encodedString, stringAllocator ); setSingleBlockValue( block, keyId, PropertyType.STRING, Iterables.first( valueRecords ).getId() ); for ( DynamicRecord valueRecord : valueRecords ) { valueRecord.setType( PropertyType.STRING.intValue() ); } block.setValueRecords( valueRecords ); }
public Value newPropertyValue( PropertyStore propertyStore ) { return getType().value( this, propertyStore ); }