// Copyright 2017 JanusGraph Authors // // 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.janusgraph.diskstorage.util; import com.google.common.base.Preconditions; import org.janusgraph.diskstorage.*; import org.janusgraph.graphdb.database.idhandling.VariableLong; import org.janusgraph.graphdb.database.serialize.DataOutput; import org.janusgraph.graphdb.database.serialize.Serializer; import java.nio.ByteBuffer; import java.util.Map; /** * Utility methods for dealing with {@link ByteBuffer}. * */ public class BufferUtil { public static final int longSize = StaticArrayBuffer.LONG_LEN; public static final int intSize = StaticArrayBuffer.INT_LEN; /* ############### * Simple StaticBuffer construction * ################ */ public static final StaticBuffer getIntBuffer(int id) { ByteBuffer buffer = ByteBuffer.allocate(intSize); buffer.putInt(id); byte[] arr = buffer.array(); Preconditions.checkArgument(arr.length == intSize); return StaticArrayBuffer.of(arr); } public static final StaticBuffer getIntBuffer(int[] ids) { ByteBuffer buffer = ByteBuffer.allocate(intSize * ids.length); for (int i = 0; i < ids.length; i++) buffer.putInt(ids[i]); byte[] arr = buffer.array(); Preconditions.checkArgument(arr.length == intSize * ids.length); return StaticArrayBuffer.of(arr); } public static final StaticBuffer getLongBuffer(long id) { ByteBuffer buffer = ByteBuffer.allocate(longSize); buffer.putLong(id); byte[] arr = buffer.array(); Preconditions.checkArgument(arr.length == longSize); return StaticArrayBuffer.of(arr); } public static final StaticBuffer fillBuffer(int len, byte value) { byte[] res = new byte[len]; for (int i = 0; i < len; i++) res[i]=value; return StaticArrayBuffer.of(res); } public static final StaticBuffer oneBuffer(int len) { return fillBuffer(len,(byte)-1); } public static final StaticBuffer zeroBuffer(int len) { return fillBuffer(len,(byte)0); } public static final StaticBuffer emptyBuffer() { return fillBuffer(0,(byte)0); } /* ################ * Buffer I/O * ################ */ public static void writeEntry(DataOutput out, Entry entry) { VariableLong.writePositive(out,entry.getValuePosition()); writeBuffer(out,entry); if (!entry.hasMetaData()) out.putByte((byte)0); else { Map<EntryMetaData,Object> metadata = entry.getMetaData(); assert metadata.size()>0 && metadata.size()<Byte.MAX_VALUE; assert EntryMetaData.values().length<Byte.MAX_VALUE; out.putByte((byte)metadata.size()); for (Map.Entry<EntryMetaData,Object> metas : metadata.entrySet()) { EntryMetaData meta = metas.getKey(); out.putByte((byte)meta.ordinal()); out.writeObjectNotNull(metas.getValue()); } } } public static void writeBuffer(DataOutput out, StaticBuffer buffer) { VariableLong.writePositive(out,buffer.length()); out.putBytes(buffer); } public static Entry readEntry(ReadBuffer in, Serializer serializer) { long valuePosition = VariableLong.readPositive(in); Preconditions.checkArgument(valuePosition>0 && valuePosition<=Integer.MAX_VALUE); StaticBuffer buffer = readBuffer(in); StaticArrayEntry entry = new StaticArrayEntry(buffer, (int) valuePosition); int metaSize = in.getByte(); for (int i=0;i<metaSize;i++) { EntryMetaData meta = EntryMetaData.values()[in.getByte()]; entry.setMetaData(meta,serializer.readObjectNotNull(in,meta.getDataType())); } return entry; } public static StaticBuffer readBuffer(ScanBuffer in) { long length = VariableLong.readPositive(in); Preconditions.checkArgument(length>=0 && length<=Integer.MAX_VALUE); byte[] data = in.getBytes((int)length); assert data.length==length; return new StaticArrayBuffer(data); } /* ################ * StaticBuffer Manipulation * ################ */ public static StaticBuffer padBuffer(StaticBuffer b, int length) { if (b.length()>=length) return b; byte[] data = new byte[length]; //implicitly initialized to all 0s for (int i = 0; i < b.length(); i++) { data[i]=b.getByte(i); } return new StaticArrayBuffer(data); } public static final StaticBuffer nextBiggerBufferAllowOverflow(StaticBuffer buffer) { return nextBiggerBuffer(buffer, true); } public static final StaticBuffer nextBiggerBuffer(StaticBuffer buffer) { return nextBiggerBuffer(buffer,false); } private static final StaticBuffer nextBiggerBuffer(StaticBuffer buffer, boolean allowOverflow) { int len = buffer.length(); byte[] next = new byte[len]; boolean carry = true; for (int i = len - 1; i >= 0; i--) { byte b = buffer.getByte(i); if (carry) { b++; if (b != 0) carry = false; } next[i]=b; } if (carry && allowOverflow) { return zeroBuffer(len); } else if (carry) { throw new IllegalArgumentException("Buffer overflow incrementing " + buffer); } else { return StaticArrayBuffer.of(next); } } /** * Thread safe equals method for StaticBuffer - ByteBuffer equality comparison * * @param b1 * @param b2 * @return */ public static final boolean equals(StaticBuffer b1, ByteBuffer b2) { if (b1.length()!=b2.remaining()) return false; int p2 = b2.position(); for (int i=0;i<b1.length();i++) { if (b1.getByte(i)!=b2.get(p2+i)) return false; } return true; } }