/**
* Copyright 2013 Oak Ridge National Laboratory
* Author: James Horey <horeyjl@ornl.gov>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
package gov.ornl.keva.table;
/**
* Keva libs.
**/
import gov.ornl.keva.core.VectorClock;
import gov.ornl.keva.core.SingletonIterator;
/**
* Java libs.
**/
import java.util.Iterator;
import java.nio.ByteBuffer;
/**
* Simple table value implementation that stores the data as an array of bytes.
*
* @author James Horey
*/
public class TableEmbedded extends TableValue {
private ByteBuffer data;
private byte[] serialized;
public TableEmbedded() {
super(TableValue.EMBED);
data = null;
serialized = null;
}
/**
* Set the data.
*
* @param value Data to use for this value
*/
public void setData(byte[] value) {
data = ByteBuffer.wrap(value);
}
/**
* Get all the data associated with this value.
*
* @return Table value data
*/
@Override public byte[] getData() {
return data.array();
}
/**
* Serialize the table value.
*
* @return Serialized table value
*/
@Override public byte[] getBytes() {
if(serialized != null) {
return serialized;
}
byte[] attr = null;
int vclockSize = 0;
int size = (Short.SIZE / 8); // Storage type.
// Get the attributes.
size += (Integer.SIZE / 8);
if(getAttributes() != null) {
attr = getAttributes().serialize();
size += attr.length;
}
// Get the vector clock.
vclockSize = getClock().memory();
size += (Integer.SIZE / 8) + vclockSize;
// Size of the actual data buffer.
size += data.capacity();
// Allocate the buffer. In this instance,
// the initial cost of "allocateDirect" seems to be
// higher than what its worth.
ByteBuffer buffer = ByteBuffer.allocate(size);
// Write out the storage type.
buffer.putShort(storageType);
// Write out the attributes.
if(attr == null) {
buffer.putInt(0);
}
else {
buffer.putInt(attr.length);
buffer.put(attr);
}
// Write out the clock.
buffer.putInt(vclockSize);
getClock().serialize(buffer);
// Write out the data.
buffer.put(data);
// Now get the serialized data.
buffer.flip();
serialized = buffer.array();
return serialized;
}
/**
* Instantiate this table from the buffer.
*
* @param buffer Buffer that contains the value data.
*/
public void fromBytes(ByteBuffer buffer) {
// First check if there were any attributes.
TableAttributes attr = null;
int attrSize = buffer.getInt();
if(attrSize > 0) {
byte[] attrBuffer = new byte[attrSize];
buffer.get(attrBuffer);
attr = new TableAttributes();
attr.unSerialize(attrBuffer);
setAttributes(attr);
}
// Now parse the vector clock.
int clockLength = buffer.getInt();
byte[] clockBuffer = new byte[clockLength];
buffer.get(clockBuffer);
VectorClock c = new VectorClock();
c.unSerialize(clockBuffer);
setClock(c);
// Now parse the actual data.
byte[] dataBuffer = new byte[buffer.remaining()];
buffer.get(dataBuffer);
setData(dataBuffer);
}
/**
* Get the size of the data.
*
* @return Size of the data in bytes
*/
@Override public long size() {
return data.capacity();
}
/**
* Get the memory usage of the data. This is usually
* the same as the "size", but not always.
*
* @return Bytes used
*/
@Override public long memory() {
return data.capacity();
}
/**
* Iterate over the internal values. Since an embedded
* type is just a single value, use a singleton iterator.
*
* @return Iterator over the internal values
*/
@Override public Iterator<? extends TableValue> iterator() {
return new SingletonIterator<TableValue>(this);
}
}