private FutureRecordMetadata futureRecordMetadata(ProduceRequestResult produceRequestResult) { return new FutureRecordMetadata( produceRequestResult, 0, RecordBatch.NO_TIMESTAMP, 0L, 0, 0, time ); }
/** * This method is only used by {@link #split(int)} when splitting a large batch to smaller ones. * @return true if the record has been successfully appended, false otherwise. */ private boolean tryAppendForSplit(long timestamp, ByteBuffer key, ByteBuffer value, Header[] headers, Thunk thunk) { if (!recordsBuilder.hasRoomFor(timestamp, key, value, headers)) { return false; } else { // No need to get the CRC. this.recordsBuilder.append(timestamp, key, value, headers); this.maxRecordSize = Math.max(this.maxRecordSize, AbstractRecords.estimateSizeInBytesUpperBound(magic(), recordsBuilder.compressionType(), key, value, headers)); FutureRecordMetadata future = new FutureRecordMetadata(this.produceFuture, this.recordCount, timestamp, thunk.future.checksumOrNull(), key == null ? -1 : key.remaining(), value == null ? -1 : value.remaining(), Time.SYSTEM); // Chain the future to the original thunk. thunk.future.chain(future); this.thunks.add(thunk); this.recordCount++; return true; } }
/** * Append the record to the current record set and return the relative offset within that record set * * @return The RecordSend corresponding to this record or null if there isn't sufficient room. */ public FutureRecordMetadata tryAppend(long timestamp, byte[] key, byte[] value, Header[] headers, Callback callback, long now) { if (!recordsBuilder.hasRoomFor(timestamp, key, value, headers)) { return null; } else { Long checksum = this.recordsBuilder.append(timestamp, key, value, headers); this.maxRecordSize = Math.max(this.maxRecordSize, AbstractRecords.estimateSizeInBytesUpperBound(magic(), recordsBuilder.compressionType(), key, value, headers)); this.lastAppendTime = now; FutureRecordMetadata future = new FutureRecordMetadata(this.produceFuture, this.recordCount, timestamp, checksum, key == null ? -1 : key.length, value == null ? -1 : value.length, Time.SYSTEM); // we have to keep every future returned to the users in case the batch needs to be // split to several new batches and resent. thunks.add(new Thunk(callback, future)); this.recordCount++; return future; } }
TopicPartition topicPartition = new TopicPartition(record.topic(), partition); ProduceRequestResult result = new ProduceRequestResult(topicPartition); FutureRecordMetadata future = new FutureRecordMetadata(result, 0, RecordBatch.NO_TIMESTAMP, 0L, 0, 0, Time.SYSTEM); long offset = nextOffset(topicPartition);
/** * Test that an asynchronous request will eventually throw the right exception */ @Test(expected = ExecutionException.class) public void testError() throws Exception { FutureRecordMetadata future = new FutureRecordMetadata(asyncRequest(baseOffset, new CorruptRecordException(), 50L), relOffset, RecordBatch.NO_TIMESTAMP, 0L, 0, 0, Time.SYSTEM); future.get(); }
/** * Test that an asynchronous request will eventually return the right offset */ @Test public void testBlocking() throws Exception { FutureRecordMetadata future = new FutureRecordMetadata(asyncRequest(baseOffset, null, 50L), relOffset, RecordBatch.NO_TIMESTAMP, 0L, 0, 0, Time.SYSTEM); assertEquals(baseOffset + relOffset, future.get().offset()); }
/** * Test that waiting on a request that never completes times out */ @Test public void testTimeout() throws Exception { ProduceRequestResult request = new ProduceRequestResult(topicPartition); FutureRecordMetadata future = new FutureRecordMetadata(request, relOffset, RecordBatch.NO_TIMESTAMP, 0L, 0, 0, Time.SYSTEM); assertFalse("Request is not completed", future.isDone()); try { future.get(5, TimeUnit.MILLISECONDS); fail("Should have thrown exception."); } catch (TimeoutException e) { /* this is good */ } request.set(baseOffset, RecordBatch.NO_TIMESTAMP, null); request.done(); assertTrue(future.isDone()); assertEquals(baseOffset + relOffset, future.get().offset()); }
/** * Append the record to the current record set and return the relative offset within that record set * * @return The RecordSend corresponding to this record or null if there isn't sufficient room. */ public FutureRecordMetadata tryAppend(byte[] key, byte[] value, Callback callback) { if (!this.records.hasRoomFor(key, value)) { return null; } else { this.records.append(0L, key, value); this.maxRecordSize = Math.max(this.maxRecordSize, Record.recordSize(key, value)); FutureRecordMetadata future = new FutureRecordMetadata(this.produceFuture, this.recordCount); if (callback != null) thunks.add(new Thunk(callback, future)); this.recordCount++; return future; } }
/** * Adds the record to the list of sent records. * * @see #history() */ @Override public synchronized Future<RecordMetadata> send(ProducerRecord<byte[],byte[]> record, Callback callback) { int partition = 0; if (this.cluster.partitionsForTopic(record.topic()) != null) partition = partitioner.partition(record, this.cluster); ProduceRequestResult result = new ProduceRequestResult(); FutureRecordMetadata future = new FutureRecordMetadata(result, 0); TopicPartition topicPartition = new TopicPartition(record.topic(), partition); long offset = nextOffset(topicPartition); Completion completion = new Completion(topicPartition, offset, new RecordMetadata(topicPartition, 0, offset), result, callback); this.sent.add(record); if (autoComplete) completion.complete(null); else this.completions.addLast(completion); return future; }