/**
* Copyright (c) 2002-2013 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.kernel.impl.storemigration;
import java.util.ArrayList;
import java.util.List;
import org.neo4j.helpers.Pair;
import org.neo4j.kernel.impl.nioneo.store.PropertyBlock;
import org.neo4j.kernel.impl.nioneo.store.PropertyRecord;
import org.neo4j.kernel.impl.nioneo.store.PropertyStore;
import org.neo4j.kernel.impl.nioneo.store.PropertyType;
import org.neo4j.kernel.impl.nioneo.store.Record;
public class PropertyWriter
{
private PropertyStore propertyStore;
public PropertyWriter( PropertyStore propertyStore )
{
this.propertyStore = propertyStore;
}
/**
* Transforms a mapping of key index ids to values into a property chain.
* Mostly copied-pasted from BatchTransactionImpl.
*
* @param properties The mapping, as a list of Pairs of keys and values
* @return a long value valid for a property record id that is the id of the
* head of the chain, suitable for a nextProp() value on a
* primitive.
*/
public long writeProperties( List<Pair<Integer, Object>> properties )
{
if ( properties == null || properties.isEmpty() )
{
return Record.NO_NEXT_PROPERTY.intValue();
}
// To hold the records, we will write them out in reverse order
List<PropertyRecord> propRecords = new ArrayList<PropertyRecord>();
// There is at least one property, so we will create at least one record.
PropertyRecord currentRecord = new PropertyRecord( propertyStore.nextId() );
currentRecord.setInUse( true );
currentRecord.setCreated();
propRecords.add( currentRecord );
for ( Pair<Integer, Object> propertyDatum : properties )
{
PropertyBlock block = new PropertyBlock();
propertyStore.encodeValue( block, propertyDatum.first(),
propertyDatum.other() );
if ( currentRecord.size() + block.getSize() > PropertyType.getPayloadSize() )
{
// Here it means the current block is done for
PropertyRecord prevRecord = currentRecord;
// Create new record
long propertyId = propertyStore.nextId();
currentRecord = new PropertyRecord( propertyId );
currentRecord.setInUse( true );
currentRecord.setCreated();
// Set up links
prevRecord.setNextProp( propertyId );
currentRecord.setPrevProp( prevRecord.getId() );
propRecords.add( currentRecord );
// Now current is ready to start picking up blocks
}
currentRecord.addPropertyBlock( block );
}
/*
* Add the property records in reverse order, which means largest
* id first. That is to make sure we expand the property store file
* only once.
*/
for ( int i = propRecords.size() - 1; i >= 0; i-- )
{
propertyStore.updateRecord( propRecords.get( i ) );
}
/*
* 0 will always exist, if the map was empty we wouldn't be here
* and even one property will create at least one record.
*/
return propRecords.get( 0 ).getId();
}
}