commit
ea189b320c
@ -0,0 +1,115 @@ |
||||
package org.rocksdb; |
||||
|
||||
/** |
||||
* <p>A TransactionLogIterator is used to iterate over the transactions in a db. |
||||
* One run of the iterator is continuous, i.e. the iterator will stop at the |
||||
* beginning of any gap in sequences.</p> |
||||
*/ |
||||
public class TransactionLogIterator extends RocksObject { |
||||
|
||||
/** |
||||
* <p>An iterator is either positioned at a WriteBatch |
||||
* or not valid. This method returns true if the iterator |
||||
* is valid. Can read data from a valid iterator.</p> |
||||
* |
||||
* @return true if iterator position is valid. |
||||
*/ |
||||
public boolean isValid() { |
||||
return isValid(nativeHandle_); |
||||
} |
||||
|
||||
/** |
||||
* <p>Moves the iterator to the next WriteBatch. |
||||
* <strong>REQUIRES</strong>: Valid() to be true.</p> |
||||
*/ |
||||
public void next() { |
||||
next(nativeHandle_); |
||||
} |
||||
|
||||
/** |
||||
* <p>Throws RocksDBException if something went wrong.</p> |
||||
* |
||||
* @throws org.rocksdb.RocksDBException if something went |
||||
* wrong in the underlying C++ code. |
||||
*/ |
||||
public void status() throws RocksDBException { |
||||
status(nativeHandle_); |
||||
} |
||||
|
||||
/** |
||||
* <p>If iterator position is valid, return the current |
||||
* write_batch and the sequence number of the earliest |
||||
* transaction contained in the batch.</p> |
||||
* |
||||
* <p>ONLY use if Valid() is true and status() is OK.</p> |
||||
* |
||||
* @return {@link org.rocksdb.TransactionLogIterator.BatchResult} |
||||
* instance. |
||||
*/ |
||||
public BatchResult getBatch() { |
||||
assert(isValid()); |
||||
return getBatch(nativeHandle_); |
||||
} |
||||
|
||||
/** |
||||
* <p>TransactionLogIterator constructor.</p> |
||||
* |
||||
* @param nativeHandle address to native address. |
||||
*/ |
||||
TransactionLogIterator(long nativeHandle) { |
||||
super(); |
||||
nativeHandle_ = nativeHandle; |
||||
} |
||||
|
||||
@Override protected void disposeInternal() { |
||||
disposeInternal(nativeHandle_); |
||||
} |
||||
|
||||
/** |
||||
* <p>BatchResult represents a data structure returned |
||||
* by a TransactionLogIterator containing a sequence |
||||
* number and a {@link WriteBatch} instance.</p> |
||||
*/ |
||||
public class BatchResult { |
||||
/** |
||||
* <p>Constructor of BatchResult class.</p> |
||||
* |
||||
* @param sequenceNumber related to this BatchResult instance. |
||||
* @param nativeHandle to {@link org.rocksdb.WriteBatch} |
||||
* native instance. |
||||
*/ |
||||
public BatchResult(long sequenceNumber, long nativeHandle) { |
||||
sequenceNumber_ = sequenceNumber; |
||||
writeBatch_ = new WriteBatch(nativeHandle); |
||||
} |
||||
|
||||
/** |
||||
* <p>Return sequence number related to this BatchResult.</p> |
||||
* |
||||
* @return Sequence number. |
||||
*/ |
||||
public long sequenceNumber() { |
||||
return sequenceNumber_; |
||||
} |
||||
|
||||
/** |
||||
* <p>Return contained {@link org.rocksdb.WriteBatch} |
||||
* instance</p> |
||||
* |
||||
* @return {@link org.rocksdb.WriteBatch} instance. |
||||
*/ |
||||
public WriteBatch writeBatch() { |
||||
return writeBatch_; |
||||
} |
||||
|
||||
private final long sequenceNumber_; |
||||
private final WriteBatch writeBatch_; |
||||
} |
||||
|
||||
private native void disposeInternal(long handle); |
||||
private native boolean isValid(long handle); |
||||
private native void next(long handle); |
||||
private native void status(long handle) |
||||
throws RocksDBException; |
||||
private native BatchResult getBatch(long handle); |
||||
} |
@ -0,0 +1,183 @@ |
||||
package org.rocksdb.test; |
||||
|
||||
import org.junit.ClassRule; |
||||
import org.junit.Rule; |
||||
import org.junit.Test; |
||||
import org.junit.rules.TemporaryFolder; |
||||
import org.rocksdb.*; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
public class TransactionLogIteratorTest { |
||||
@ClassRule |
||||
public static final RocksMemoryResource rocksMemoryResource = |
||||
new RocksMemoryResource(); |
||||
|
||||
@Rule |
||||
public TemporaryFolder dbFolder = new TemporaryFolder(); |
||||
|
||||
@Test |
||||
public void transactionLogIterator() throws RocksDBException { |
||||
RocksDB db = null; |
||||
Options options = null; |
||||
TransactionLogIterator transactionLogIterator = null; |
||||
try { |
||||
options = new Options(). |
||||
setCreateIfMissing(true); |
||||
db = RocksDB.open(options, dbFolder.getRoot().getAbsolutePath()); |
||||
transactionLogIterator = db.getUpdatesSince(0); |
||||
} finally { |
||||
if (transactionLogIterator != null) { |
||||
transactionLogIterator.dispose(); |
||||
} |
||||
if (db != null) { |
||||
db.close(); |
||||
} |
||||
if (options != null) { |
||||
options.dispose(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
public void getBatch() throws RocksDBException { |
||||
final int numberOfPuts = 5; |
||||
RocksDB db = null; |
||||
Options options = null; |
||||
ColumnFamilyHandle cfHandle = null; |
||||
TransactionLogIterator transactionLogIterator = null; |
||||
try { |
||||
options = new Options(). |
||||
setCreateIfMissing(true). |
||||
setWalTtlSeconds(1000). |
||||
setWalSizeLimitMB(10); |
||||
|
||||
db = RocksDB.open(options, dbFolder.getRoot().getAbsolutePath()); |
||||
|
||||
for (int i = 0; i < numberOfPuts; i++){ |
||||
db.put(String.valueOf(i).getBytes(), |
||||
String.valueOf(i).getBytes()); |
||||
} |
||||
db.flush(new FlushOptions().setWaitForFlush(true)); |
||||
|
||||
// the latest sequence number is 5 because 5 puts
|
||||
// were written beforehand
|
||||
assertThat(db.getLatestSequenceNumber()). |
||||
isEqualTo(numberOfPuts); |
||||
|
||||
// insert 5 writes into a cf
|
||||
cfHandle = db.createColumnFamily( |
||||
new ColumnFamilyDescriptor("new_cf".getBytes())); |
||||
|
||||
for (int i = 0; i < numberOfPuts; i++){ |
||||
db.put(cfHandle, String.valueOf(i).getBytes(), |
||||
String.valueOf(i).getBytes()); |
||||
} |
||||
// the latest sequence number is 10 because
|
||||
// (5 + 5) puts were written beforehand
|
||||
assertThat(db.getLatestSequenceNumber()). |
||||
isEqualTo(numberOfPuts + numberOfPuts); |
||||
|
||||
// Get updates since the beginning
|
||||
transactionLogIterator = db.getUpdatesSince(0); |
||||
assertThat(transactionLogIterator.isValid()).isTrue(); |
||||
transactionLogIterator.status(); |
||||
|
||||
// The first sequence number is 1
|
||||
TransactionLogIterator.BatchResult batchResult = |
||||
transactionLogIterator.getBatch(); |
||||
assertThat(batchResult.sequenceNumber()).isEqualTo(1); |
||||
} finally { |
||||
if (transactionLogIterator != null) { |
||||
transactionLogIterator.dispose(); |
||||
} |
||||
if (cfHandle != null) { |
||||
cfHandle.dispose(); |
||||
} |
||||
if (db != null) { |
||||
db.close(); |
||||
} |
||||
if (options != null) { |
||||
options.dispose(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
public void transactionLogIteratorStallAtLastRecord() throws RocksDBException { |
||||
RocksDB db = null; |
||||
Options options = null; |
||||
TransactionLogIterator transactionLogIterator = null; |
||||
try { |
||||
options = new Options(). |
||||
setCreateIfMissing(true). |
||||
setWalTtlSeconds(1000). |
||||
setWalSizeLimitMB(10); |
||||
|
||||
db = RocksDB.open(options, dbFolder.getRoot().getAbsolutePath()); |
||||
db.put("key1".getBytes(), "value1".getBytes()); |
||||
// Get updates since the beginning
|
||||
transactionLogIterator = db.getUpdatesSince(0); |
||||
transactionLogIterator.status(); |
||||
assertThat(transactionLogIterator.isValid()).isTrue(); |
||||
transactionLogIterator.next(); |
||||
assertThat(transactionLogIterator.isValid()).isFalse(); |
||||
transactionLogIterator.status(); |
||||
db.put("key2".getBytes(), "value2".getBytes()); |
||||
transactionLogIterator.next(); |
||||
transactionLogIterator.status(); |
||||
assertThat(transactionLogIterator.isValid()).isTrue(); |
||||
|
||||
} finally { |
||||
if (transactionLogIterator != null) { |
||||
transactionLogIterator.dispose(); |
||||
} |
||||
if (db != null) { |
||||
db.close(); |
||||
} |
||||
if (options != null) { |
||||
options.dispose(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
public void transactionLogIteratorCheckAfterRestart() throws RocksDBException { |
||||
final int numberOfKeys = 2; |
||||
RocksDB db = null; |
||||
Options options = null; |
||||
TransactionLogIterator transactionLogIterator = null; |
||||
try { |
||||
options = new Options(). |
||||
setCreateIfMissing(true). |
||||
setWalTtlSeconds(1000). |
||||
setWalSizeLimitMB(10); |
||||
|
||||
db = RocksDB.open(options, dbFolder.getRoot().getAbsolutePath()); |
||||
db.put("key1".getBytes(), "value1".getBytes()); |
||||
db.put("key2".getBytes(), "value2".getBytes()); |
||||
db.flush(new FlushOptions().setWaitForFlush(true)); |
||||
// reopen
|
||||
db.close(); |
||||
db = RocksDB.open(options, dbFolder.getRoot().getAbsolutePath()); |
||||
assertThat(db.getLatestSequenceNumber()).isEqualTo(numberOfKeys); |
||||
|
||||
transactionLogIterator = db.getUpdatesSince(0); |
||||
for (int i = 0; i < numberOfKeys; i++) { |
||||
transactionLogIterator.status(); |
||||
assertThat(transactionLogIterator.isValid()).isTrue(); |
||||
transactionLogIterator.next(); |
||||
} |
||||
} finally { |
||||
if (transactionLogIterator != null) { |
||||
transactionLogIterator.dispose(); |
||||
} |
||||
if (db != null) { |
||||
db.close(); |
||||
} |
||||
if (options != null) { |
||||
options.dispose(); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,78 @@ |
||||
// Copyright (c) 2014, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
// This file implements the "bridge" between Java and C++ and enables
|
||||
// calling c++ rocksdb::Iterator methods from Java side.
|
||||
|
||||
#include <jni.h> |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
|
||||
#include "include/org_rocksdb_TransactionLogIterator.h" |
||||
#include "rocksdb/transaction_log.h" |
||||
#include "rocksjni/portal.h" |
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionLogIterator |
||||
* Method: disposeInternal |
||||
* Signature: (J)V |
||||
*/ |
||||
void Java_org_rocksdb_TransactionLogIterator_disposeInternal( |
||||
JNIEnv* env, jobject jobj, jlong handle) { |
||||
delete reinterpret_cast<rocksdb::TransactionLogIterator*>(handle); |
||||
} |
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionLogIterator |
||||
* Method: isValid |
||||
* Signature: (J)Z |
||||
*/ |
||||
jboolean Java_org_rocksdb_TransactionLogIterator_isValid( |
||||
JNIEnv* env, jobject jobj, jlong handle) { |
||||
return reinterpret_cast<rocksdb::TransactionLogIterator*>(handle)->Valid(); |
||||
} |
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionLogIterator |
||||
* Method: next |
||||
* Signature: (J)V |
||||
*/ |
||||
void Java_org_rocksdb_TransactionLogIterator_next( |
||||
JNIEnv* env, jobject jobj, jlong handle) { |
||||
reinterpret_cast<rocksdb::TransactionLogIterator*>(handle)->Next(); |
||||
} |
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionLogIterator |
||||
* Method: status |
||||
* Signature: (J)V |
||||
*/ |
||||
void Java_org_rocksdb_TransactionLogIterator_status( |
||||
JNIEnv* env, jobject jobj, jlong handle) { |
||||
rocksdb::Status s = reinterpret_cast< |
||||
rocksdb::TransactionLogIterator*>(handle)->status(); |
||||
if (!s.ok()) { |
||||
rocksdb::RocksDBExceptionJni::ThrowNew(env, s); |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* Class: org_rocksdb_TransactionLogIterator |
||||
* Method: getBatch |
||||
* Signature: (J)Lorg/rocksdb/TransactionLogIterator$BatchResult |
||||
*/ |
||||
jobject Java_org_rocksdb_TransactionLogIterator_getBatch( |
||||
JNIEnv* env, jobject jobj, jlong handle) { |
||||
rocksdb::BatchResult batch_result = |
||||
reinterpret_cast<rocksdb::TransactionLogIterator*>(handle)->GetBatch(); |
||||
jclass jclazz = env->FindClass( |
||||
"org/rocksdb/TransactionLogIterator$BatchResult"); |
||||
assert(jclazz != nullptr); |
||||
jmethodID mid = env->GetMethodID( |
||||
jclazz, "<init>", "(Lorg/rocksdb/TransactionLogIterator;JJ)V"); |
||||
assert(mid != nullptr); |
||||
return env->NewObject(jclazz, mid, jobj, |
||||
batch_result.sequence, batch_result.writeBatchPtr.release()); |
||||
} |
Loading…
Reference in new issue