All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bboxdb.storage.util.TupleHelper Maven / Gradle / Ivy

There is a newer version: 1.0.0-rc3
Show newest version
/*******************************************************************************
 *
 *    Copyright (C) 2015-2018 the BBoxDB project
 *  
 *    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 org.bboxdb.storage.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Comparator;

import org.bboxdb.commons.io.DataEncoderHelper;
import org.bboxdb.commons.math.Hyperrectangle;
import org.bboxdb.storage.entity.DeletedTuple;
import org.bboxdb.storage.entity.Tuple;
import org.bboxdb.storage.sstable.SSTableConst;

import com.google.common.io.ByteStreams;

public class TupleHelper {
	
	/**
	 * Compare the tuples by key
	 */
	public final static Comparator TUPLE_KEY_COMPARATOR = 
			(t1, t2) -> {
				return t1.getKey().compareTo(t2.getKey());
			};
	
	/**
	 * Compare the tuples by key and version
	 */
	public final static Comparator TUPLE_KEY_AND_VERSION_COMPARATOR = 
			(t1, t2) -> {
				
				final int keyCompare = t1.getKey().compareTo(t2.getKey());
				
				if(keyCompare != 0) {
					return keyCompare;
				}
				
				return Long.compare(t1.getVersionTimestamp(), t2.getVersionTimestamp());
			};
	
	/**
	 * Return the most recent version of the tuple
	 * @param tuple1
	 * @param tuple2
	 * @return
	 */
	public static Tuple returnMostRecentTuple(final Tuple tuple1, final Tuple tuple2) {
		if(tuple1 == null && tuple2 == null) {
			return null;
		}
		
		if(tuple1 == null) {
			return tuple2;
		}
		
		if(tuple2 == null) {
			return tuple1;
		}
		
		if(tuple1.getVersionTimestamp() > tuple2.getVersionTimestamp()) {
			return tuple1;
		}
		
		return tuple2;
	}
	
	/**
	 * Write the given tuple onto the output Stream
	 * 
	 * Format of a data record:
	 * 
	 * +----------------------------------------------------------------------------------------------+
	 * | Key-Length | BBox-Length | Data-Length |  Version  |  Insert   |   Key   |  BBox   |   Data  |
	 * |            |             |             | Timestamp | Timestamp |         |         |         |
	 * |   2 Byte   |   4 Byte    |   4 Byte    |  8 Byte   |  8 Byte   |  n Byte |  n Byte |  n Byte |
	 * +----------------------------------------------------------------------------------------------+
	 * 
	 * 
	 * @param tuple
	 * @throws IOException
	 */
	public static void writeTupleToStream(final Tuple tuple, final OutputStream outputStream) throws IOException {
		final byte[] keyBytes = tuple.getKey().getBytes();
		final ByteBuffer keyLengthBytes = DataEncoderHelper.shortToByteBuffer((short) keyBytes.length);

		final byte[] boundingBoxBytes = tuple.getBoundingBoxBytes();
		final byte[] data = tuple.getDataBytes();
		
		final ByteBuffer boxLengthBytes = DataEncoderHelper.intToByteBuffer(boundingBoxBytes.length);
		final ByteBuffer dataLengthBytes = DataEncoderHelper.intToByteBuffer(data.length);
		final ByteBuffer versionTimestampBytes = DataEncoderHelper.longToByteBuffer(tuple.getVersionTimestamp());
		final ByteBuffer receivedTimestampBytes = DataEncoderHelper.longToByteBuffer(tuple.getReceivedTimestamp());

		outputStream.write(keyLengthBytes.array());
		outputStream.write(boxLengthBytes.array());
		outputStream.write(dataLengthBytes.array());
		outputStream.write(versionTimestampBytes.array());
		outputStream.write(receivedTimestampBytes.array());
		outputStream.write(keyBytes);
		outputStream.write(boundingBoxBytes);
		outputStream.write(data);
	}
	
	/**
	 * Convert the tuple into bytes
	 * @param tuple
	 * @return
	 * @throws IOException
	 */
	public static byte[] tupleToBytes(final Tuple tuple) throws IOException {
		final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
		writeTupleToStream(tuple, outputStream);
		outputStream.close();
		return outputStream.toByteArray();
	}
	
	/**
	 * Decode the tuple at the current reader position
	 * 
	 * @param reader
	 * @return
	 * @throws IOException
	 */
	public static Tuple decodeTuple(final ByteBuffer byteBuffer) throws IOException {
		final short keyLength = byteBuffer.getShort();
		final int boxLength = byteBuffer.getInt();
		final int dataLength = byteBuffer.getInt();
		final long versionTimestamp = byteBuffer.getLong();
		final long receivedTimestamp = byteBuffer.getLong();

		final byte[] keyBytes = new byte[keyLength];
		byteBuffer.get(keyBytes, 0, keyBytes.length);
		
		final byte[] boxBytes = new byte[boxLength];
		byteBuffer.get(boxBytes, 0, boxBytes.length);
		
		final byte[] dataBytes = new byte[dataLength];
		byteBuffer.get(dataBytes, 0, dataBytes.length);				
		
		final String keyString = new String(keyBytes);
		
		if(isDeletedTuple(boxBytes, dataBytes)) {
			return new DeletedTuple(keyString, versionTimestamp);
		}
		
		final Hyperrectangle boundingBox = Hyperrectangle.fromByteArray(boxBytes);
		
		return new Tuple(keyString, boundingBox, dataBytes, versionTimestamp, receivedTimestamp);
	}
	
	/**
	 * Read the tuple from the input stream
	 * @param inputStream
	 * @return
	 * @throws IOException 
	 */
	public static Tuple decodeTuple(final InputStream inputStream) throws IOException {
		final byte[] keyLengthBytes = new byte[DataEncoderHelper.SHORT_BYTES];
		ByteStreams.readFully(inputStream, keyLengthBytes);
		final short keyLength = DataEncoderHelper.readShortFromByte(keyLengthBytes);
		
		final byte[] boxLengthBytes = new byte[DataEncoderHelper.INT_BYTES];
		ByteStreams.readFully(inputStream, boxLengthBytes);
		final int boxLength = DataEncoderHelper.readIntFromByte(boxLengthBytes);

		final byte[] dataLengthBytes = new byte[DataEncoderHelper.INT_BYTES];
		ByteStreams.readFully(inputStream, dataLengthBytes);
		final int dataLength = DataEncoderHelper.readIntFromByte(dataLengthBytes);

		final byte[] versionTimestampBytes = new byte[DataEncoderHelper.LONG_BYTES];
		ByteStreams.readFully(inputStream, versionTimestampBytes);
		final long versionTimestamp = DataEncoderHelper.readLongFromByte(versionTimestampBytes);

		final byte[] receivedTimestampBytes = new byte[DataEncoderHelper.LONG_BYTES];
		ByteStreams.readFully(inputStream, receivedTimestampBytes);
		final long receivedTimestamp = DataEncoderHelper.readLongFromByte(receivedTimestampBytes);

		final byte[] keyBytes = new byte[keyLength];
		ByteStreams.readFully(inputStream, keyBytes);
		
		final byte[] boxBytes = new byte[boxLength];
		ByteStreams.readFully(inputStream, boxBytes);
		
		final byte[] dataBytes = new byte[dataLength];
		ByteStreams.readFully(inputStream, dataBytes);		

		final String keyString = new String(keyBytes);

		if(isDeletedTuple(boxBytes, dataBytes)) {
			return new DeletedTuple(keyString, versionTimestamp);
		}
						
		final Hyperrectangle boundingBox = Hyperrectangle.fromByteArray(boxBytes);
		
		return new Tuple(keyString, boundingBox, dataBytes, versionTimestamp, receivedTimestamp);
	}
	
	/**
	 * Is this a deleted tuple?
	 * @param tuple
	 * @return
	 */
	public static boolean isDeletedTuple(final Tuple tuple) {
		if(tuple.getBoundingBox() == Hyperrectangle.FULL_SPACE) {
			if(Arrays.equals(tuple.getDataBytes(), SSTableConst.DELETED_MARKER)) {
				return true;
			}
		}
		
		return false;
	}
	
	/**
	 * Is this a deleted tuple?
	 * @param boxBytes
	 * @param dataBytes
	 * @return
	 */
	public static boolean isDeletedTuple(final byte[] boxBytes, final byte[] dataBytes) {
		if(Arrays.equals(dataBytes,SSTableConst.DELETED_MARKER)) {
			if(Arrays.equals(boxBytes, SSTableConst.DELETED_MARKER)) {
				return true;
			}
		}
		
		return false;
	}
	
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy