/** * Calculate the number of data bytes for the given id. As the length is encoded in the id, this * operation does not cause any reads in the map. * * @param id the id * @return the length */ public long length(byte[] id) { ByteBuffer idBuffer = ByteBuffer.wrap(id); long length = 0; while (idBuffer.hasRemaining()) { switch (idBuffer.get()) { case 0: // in-place: 0, len (int), data int len = DataUtils.readVarInt(idBuffer); idBuffer.position(idBuffer.position() + len); length += len; break; case 1: // block: 1, len (int), blockId (long) length += DataUtils.readVarInt(idBuffer); DataUtils.readVarLong(idBuffer); break; case 2: // indirect: 2, total len (long), blockId (long) length += DataUtils.readVarLong(idBuffer); DataUtils.readVarLong(idBuffer); break; default: throw DataUtils.newIllegalArgumentException("Unsupported id {0}", Arrays.toString(id)); } } return length; }
/** * Remove all stored blocks for the given id. * * @param id the id */ public void remove(byte[] id) { ByteBuffer idBuffer = ByteBuffer.wrap(id); while (idBuffer.hasRemaining()) { switch (idBuffer.get()) { case 0: // in-place: 0, len (int), data int len = DataUtils.readVarInt(idBuffer); idBuffer.position(idBuffer.position() + len); break; case 1: // block: 1, len (int), blockId (long) DataUtils.readVarInt(idBuffer); long k = DataUtils.readVarLong(idBuffer); map.remove(k); break; case 2: // indirect: 2, total len (long), blockId (long) DataUtils.readVarLong(idBuffer); long k2 = DataUtils.readVarLong(idBuffer); // recurse remove(map.get(k2)); map.remove(k2); break; default: throw DataUtils.newIllegalArgumentException("Unsupported id {0}", Arrays.toString(id)); } } }
/** * Get the key of the biggest block, of -1 for inline data. This method is used to garbage collect * orphaned blocks. * * @param id the id * @return the key, or -1 */ public long getMaxBlockKey(byte[] id) { long maxKey = -1; ByteBuffer idBuffer = ByteBuffer.wrap(id); while (idBuffer.hasRemaining()) { switch (idBuffer.get()) { case 0: // in-place: 0, len (int), data int len = DataUtils.readVarInt(idBuffer); idBuffer.position(idBuffer.position() + len); break; case 1: // block: 1, len (int), blockId (long) DataUtils.readVarInt(idBuffer); long k = DataUtils.readVarLong(idBuffer); maxKey = Math.max(maxKey, k); break; case 2: // indirect: 2, total len (long), blockId (long) DataUtils.readVarLong(idBuffer); long k2 = DataUtils.readVarLong(idBuffer); // recurse byte[] r = map.get(k2); maxKey = Math.max(maxKey, getMaxBlockKey(r)); break; default: throw DataUtils.newIllegalArgumentException("Unsupported id {0}", Arrays.toString(id)); } } return maxKey; }
private ByteArrayInputStream nextBuffer() { while (idBuffer.hasRemaining()) { switch (idBuffer.get()) { case 0: { int len = DataUtils.readVarInt(idBuffer); if (skip >= len) { skip -= len; idBuffer.position(idBuffer.position() + len); continue; } int p = (int) (idBuffer.position() + skip); int l = (int) (len - skip); idBuffer.position(p + l); return new ByteArrayInputStream(idBuffer.array(), p, l); } case 1: { int len = DataUtils.readVarInt(idBuffer); long key = DataUtils.readVarLong(idBuffer); if (skip >= len) { skip -= len; continue; } byte[] data = store.getBlock(key); int s = (int) skip; skip = 0; return new ByteArrayInputStream(data, s, data.length - s); } case 2: { long len = DataUtils.readVarLong(idBuffer); long key = DataUtils.readVarLong(idBuffer); if (skip >= len) { skip -= len; continue; } byte[] k = store.getBlock(key); ByteBuffer newBuffer = ByteBuffer.allocate(k.length + idBuffer.limit() - idBuffer.position()); newBuffer.put(k); newBuffer.put(idBuffer); newBuffer.flip(); idBuffer = newBuffer; return nextBuffer(); } default: throw DataUtils.newIllegalArgumentException( "Unsupported id {0}", Arrays.toString(idBuffer.array())); } } return null; }
/** * Convert the id to a human readable string. * * @param id the stream id * @return the string */ public static String toString(byte[] id) { StringBuilder buff = new StringBuilder(); ByteBuffer idBuffer = ByteBuffer.wrap(id); long length = 0; while (idBuffer.hasRemaining()) { long block; int len; switch (idBuffer.get()) { case 0: // in-place: 0, len (int), data len = DataUtils.readVarInt(idBuffer); idBuffer.position(idBuffer.position() + len); buff.append("data len=").append(len); length += len; break; case 1: // block: 1, len (int), blockId (long) len = DataUtils.readVarInt(idBuffer); length += len; block = DataUtils.readVarLong(idBuffer); buff.append("block ").append(block).append(" len=").append(len); break; case 2: // indirect: 2, total len (long), blockId (long) len = DataUtils.readVarInt(idBuffer); length += DataUtils.readVarLong(idBuffer); block = DataUtils.readVarLong(idBuffer); buff.append("indirect block ").append(block).append(" len=").append(len); break; default: buff.append("error"); } buff.append(", "); } buff.append("length=").append(length); return buff.toString(); }