/* * Copyright © 2014 Cask Data, Inc. * * 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 co.cask.cdap.data.stream.decoder; import co.cask.cdap.api.flow.flowlet.StreamEvent; import co.cask.cdap.api.stream.StreamEventDecoder; import org.apache.hadoop.io.BytesWritable; import org.apache.hadoop.io.LongWritable; import java.nio.ByteBuffer; /** * A {@link StreamEventDecoder} that decodes {@link StreamEvent} into {@link LongWritable} as key * and {@link BytesWritable} as value for Mapper input. The key carries the event timestamp, while * the value is the stream event body. */ public final class BytesStreamEventDecoder implements StreamEventDecoder<LongWritable, BytesWritable> { private final LongWritable key = new LongWritable(); private BytesWritable value = new BytesWritable(); @Override public DecodeResult<LongWritable, BytesWritable> decode(StreamEvent event, DecodeResult<LongWritable, BytesWritable> result) { key.set(event.getTimestamp()); value = getEventBody(event, value); return result.setKey(key).setValue(value); } private BytesWritable getEventBody(StreamEvent event, BytesWritable result) { ByteBuffer body = event.getBody(); if (body.hasArray()) { // If the ByteBuffer is backed by an array, which is exactly the same as exposed by the ByteBuffer // simply use the back array. No copying is needed (because read from stream->mapper is synchronous). // Creating a new BytesWritable is more efficient as it doesn't need to do array copy, // which BytesWritable.set() does. if (body.array().length == body.remaining()) { return new BytesWritable(body.array()); } // Otherwise, need to copy the byte[], done by the BytesWritable.set() method result.set(body.array(), body.arrayOffset() + body.position(), body.remaining()); return result; } // Otherwise, need to copy to a new array byte[] copy = new byte[body.remaining()]; body.mark(); body.get(copy); body.reset(); return new BytesWritable(copy); } }