@Override public int read() throws IOException { if (currentPosition + 1 > endPosition) { throw new IndexOutOfBoundsException("Trying to read outside the available read window"); } ByteBuffer buf = ByteBuffer.allocate(1); readable.readInto(buf, currentPosition); currentPosition += 1; buf.flip(); return buf.get() & 0xFF; }
@Override public int read(byte b[], int off, int len) throws IOException { if (b == null) { throw new NullPointerException(); } else if (off < 0 || len < 0 || len > b.length - off) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } else if (currentPosition + (len - off) > endPosition) { throw new IndexOutOfBoundsException("Trying to read outside the available read window"); } ByteBuffer buf = ByteBuffer.wrap(b); buf.position(off); buf.limit(len); readable.readInto(buf, currentPosition); currentPosition += (buf.position() - off); return buf.position() - off; }
@Override public List<MessageInfo> recover( Read read, long startOffset, long endOffset, StoreKeyFactory factory) throws IOException { ArrayList<MessageInfo> messageRecovered = new ArrayList<MessageInfo>(); try { while (startOffset < endOffset) { // read message header ByteBuffer headerVersion = ByteBuffer.allocate(MessageFormatRecord.Version_Field_Size_In_Bytes); if (startOffset + MessageFormatRecord.Version_Field_Size_In_Bytes > endOffset) { throw new IndexOutOfBoundsException("Unable to read version. Reached end of stream"); } read.readInto(headerVersion, startOffset); startOffset += headerVersion.capacity(); headerVersion.flip(); short version = headerVersion.getShort(); switch (version) { case MessageFormatRecord.Message_Header_Version_V1: ByteBuffer header = ByteBuffer.allocate(MessageFormatRecord.MessageHeader_Format_V1.getHeaderSize()); header.putShort(version); if (startOffset + (MessageFormatRecord.MessageHeader_Format_V1.getHeaderSize() - headerVersion.capacity()) > endOffset) { throw new IndexOutOfBoundsException("Unable to read version. Reached end of stream"); } read.readInto(header, startOffset); startOffset += header.capacity() - headerVersion.capacity(); header.flip(); MessageFormatRecord.MessageHeader_Format_V1 headerFormat = new MessageFormatRecord.MessageHeader_Format_V1(header); headerFormat.verifyHeader(); ReadInputStream stream = new ReadInputStream(read, startOffset, endOffset); StoreKey key = factory.getStoreKey(new DataInputStream(stream)); // read the appropriate type of message based on the relative offset that is set if (headerFormat.getBlobPropertiesRecordRelativeOffset() != MessageFormatRecord.Message_Header_Invalid_Relative_Offset) { BlobProperties properties = MessageFormatRecord.deserializeBlobProperties(stream); // we do not use the user metadata or blob during recovery but we still deserialize // them to check // for validity MessageFormatRecord.deserializeUserMetadata(stream); MessageFormatRecord.deserializeBlob(stream); MessageInfo info = new MessageInfo( key, header.capacity() + key.sizeInBytes() + headerFormat.getMessageSize(), Utils.addSecondsToEpochTime( properties.getCreationTimeInMs(), properties.getTimeToLiveInSeconds())); messageRecovered.add(info); } else { boolean deleteFlag = MessageFormatRecord.deserializeDeleteRecord(stream); MessageInfo info = new MessageInfo( key, header.capacity() + key.sizeInBytes() + headerFormat.getMessageSize(), deleteFlag); messageRecovered.add(info); } startOffset = stream.getCurrentPosition(); break; default: throw new MessageFormatException( "Version not known while reading message - " + version, MessageFormatErrorCodes.Unknown_Format_Version); } } } catch (MessageFormatException e) { // log in case where we were not able to parse a message. we stop recovery at that point and // return the // messages that have been recovered so far. logger.error("Message format exception while recovering messages"); } catch (IndexOutOfBoundsException e) { // log in case where were not able to read a complete message. we stop recovery at that point // and return // the message that have been recovered so far. logger.error("Trying to read more than the available bytes"); } for (MessageInfo messageInfo : messageRecovered) { logger.info( "Message Recovered key {} size {} ttl {} deleted {}", messageInfo.getStoreKey(), messageInfo.getSize(), messageInfo.getExpirationTimeInMs(), messageInfo.isDeleted()); } return messageRecovered; }