Implement netty resources

This commit is contained in:
Andrea Cavalli 2022-05-17 23:11:31 +02:00
parent d8e835549b
commit 4f5ab8ac6a
19 changed files with 155 additions and 150 deletions

View File

@ -144,6 +144,11 @@
</build>
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty5-buffer</artifactId>
<version>5.0.0.Alpha1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>

View File

@ -63,13 +63,15 @@ public abstract class AbstractCompactionFilterFactory<T extends AbstractCompacti
public abstract String name();
/**
* We override {@link RocksCallbackObject#disposeInternal()}
* We override {@link RocksCallbackObject#disposeInternal(boolean)}
* as disposing of a rocksdb::AbstractCompactionFilterFactory requires
* a slightly different approach as it is a std::shared_ptr
*/
@Override
protected void disposeInternal() {
disposeInternal(nativeHandle_);
protected void disposeInternal(boolean owningHandle) {
if (owningHandle) {
disposeInternal(nativeHandle_);
}
}
private native long createNewCompactionFilterFactory0();

View File

@ -325,8 +325,10 @@ public abstract class AbstractEventListener extends RocksCallbackObject implemen
* Deletes underlying C++ native callback object pointer
*/
@Override
protected void disposeInternal() {
disposeInternal(nativeHandle_);
protected void disposeInternal(boolean owningHandle) {
if (owningHandle) {
disposeInternal(nativeHandle_);
}
}
private native long createNewEventListener(final long enabledEventCallbackValues);

View File

@ -5,6 +5,7 @@
package org.rocksdb;
import io.netty5.buffer.api.Drop;
import java.util.concurrent.atomic.AtomicBoolean;
/**
@ -14,21 +15,36 @@ import java.util.concurrent.atomic.AtomicBoolean;
*/
//@ThreadSafe
public abstract class AbstractImmutableNativeReference
extends AbstractNativeReference {
extends AbstractNativeReference<AbstractImmutableNativeReference> {
private static final Drop<AbstractImmutableNativeReference> DROP = new Drop<AbstractImmutableNativeReference>() {
@Override public void drop(AbstractImmutableNativeReference obj) {
obj.disposeInternal(obj.owningHandle_);
}
@Override public Drop<AbstractImmutableNativeReference> fork() {
return this;
}
@Override public void attach(AbstractImmutableNativeReference obj) {
}
};
/**
* A flag indicating whether the current {@code AbstractNativeReference} is
* responsible to free the underlying C++ object
*/
protected final AtomicBoolean owningHandle_;
protected volatile boolean owningHandle_;
protected AbstractImmutableNativeReference(final boolean owningHandle) {
this.owningHandle_ = new AtomicBoolean(owningHandle);
super(DROP);
this.owningHandle_ = owningHandle;
}
@Override
public boolean isOwningHandle() {
return owningHandle_.get();
return owningHandle_ && isAccessible();
}
/**
@ -46,14 +62,7 @@ public abstract class AbstractImmutableNativeReference
* </p>
*/
protected final void disOwnNativeHandle() {
owningHandle_.set(false);
}
@Override
public void close() {
if (owningHandle_.compareAndSet(true, false)) {
disposeInternal();
}
owningHandle_ = false;
}
/**
@ -61,5 +70,5 @@ public abstract class AbstractImmutableNativeReference
* which all subclasses of {@code AbstractImmutableNativeReference} must
* implement to release their underlying native C++ objects.
*/
protected abstract void disposeInternal();
protected abstract void disposeInternal(boolean owningHandle);
}

View File

@ -5,6 +5,10 @@
package org.rocksdb;
import io.netty5.buffer.api.Drop;
import io.netty5.buffer.api.Owned;
import io.netty5.buffer.api.internal.ResourceSupport;
/**
* AbstractNativeReference is the base-class of all RocksDB classes that have
* a pointer to a native C++ {@code rocksdb} object.
@ -26,7 +30,13 @@ package org.rocksdb;
* and cannot know what other resources depend on it.
* </p>
*/
public abstract class AbstractNativeReference implements AutoCloseable {
public abstract class AbstractNativeReference<T extends AbstractNativeReference<T>>
extends ResourceSupport<AbstractNativeReference<T>, T> {
protected AbstractNativeReference(Drop<T> drop) {
super(drop);
}
/**
* Returns true if we are responsible for freeing the underlying C++ object
*
@ -34,15 +44,12 @@ public abstract class AbstractNativeReference implements AutoCloseable {
*/
protected abstract boolean isOwningHandle();
/**
* Frees the underlying C++ object
* <p>
* It is strong recommended that the developer calls this after they
* have finished using the object.</p>
* <p>
* Note, that once an instance of {@link AbstractNativeReference} has been
* closed, calling any of its functions will lead to undefined
* behavior.</p>
*/
@Override public abstract void close();
@Override protected RuntimeException createResourceClosedException() {
return new IllegalStateException("Resource is closed");
}
@Override protected final Owned<T> prepareSend() {
throw new UnsupportedOperationException("Sends are not supported");
}
}

View File

@ -123,10 +123,12 @@ public abstract class AbstractRocksIterator<P extends RocksObject>
* before freeing the native handle.</p>
*/
@Override
protected void disposeInternal() {
protected void disposeInternal(boolean owningHandle) {
if (owningHandle) {
if (parent_.isOwningHandle()) {
disposeInternal(nativeHandle_);
}
}
}
abstract boolean isValid0(long handle);

View File

@ -47,8 +47,10 @@ public abstract class AbstractTransactionNotifier
* Otherwise an undefined behavior will occur.
*/
@Override
protected void disposeInternal() {
disposeInternal(nativeHandle_);
protected void disposeInternal(boolean owningHandle) {
if (owningHandle) {
disposeInternal(nativeHandle_);
}
}
protected final native void disposeInternal(final long handle);
}

View File

@ -136,9 +136,11 @@ public class ColumnFamilyHandle extends RocksObject {
* initialized before freeing the native handle.</p>
*/
@Override
protected void disposeInternal() {
if(rocksDB_.isOwningHandle()) {
disposeInternal(nativeHandle_);
protected void disposeInternal(boolean owningHandle) {
if (owningHandle) {
if (rocksDB_.isOwningHandle()) {
disposeInternal(nativeHandle_);
}
}
}

View File

@ -27,8 +27,10 @@ public abstract class Filter extends RocksObject {
* Otherwise an undefined behavior will occur.
*/
@Override
protected void disposeInternal() {
disposeInternal(nativeHandle_);
protected void disposeInternal(boolean owningHandle) {
if (owningHandle) {
disposeInternal(nativeHandle_);
}
}
@Override

View File

@ -109,13 +109,15 @@ public abstract class Logger extends RocksCallbackObject {
protected native byte infoLogLevel(long handle);
/**
* We override {@link RocksCallbackObject#disposeInternal()}
* We override {@link RocksCallbackObject#disposeInternal(boolean)}
* as disposing of a rocksdb::LoggerJniCallback requires
* a slightly different approach as it is a std::shared_ptr
*/
@Override
protected void disposeInternal() {
disposeInternal(nativeHandle_);
protected void disposeInternal(boolean owningHandle) {
if (owningHandle) {
disposeInternal(nativeHandle_);
}
}
private native void disposeInternal(final long handle);

View File

@ -46,13 +46,15 @@ public abstract class NativeComparatorWrapper
}
/**
* We override {@link RocksCallbackObject#disposeInternal()}
* We override {@link RocksCallbackObject#disposeInternal(boolean)}
* as disposing of a native rocksdb::Comparator extension requires
* a slightly different approach as it is not really a RocksCallbackObject
*/
@Override
protected void disposeInternal() {
disposeInternal(nativeHandle_);
protected void disposeInternal(boolean owningHandle) {
if (owningHandle) {
disposeInternal(nativeHandle_);
}
}
private native void disposeInternal(final long handle);

View File

@ -109,35 +109,23 @@ public class OptimisticTransactionDB extends RocksDB
* @throws RocksDBException if an error occurs whilst closing.
*/
public void closeE() throws RocksDBException {
if (owningHandle_.compareAndSet(true, false)) {
try {
closeDatabase(nativeHandle_);
} finally {
disposeInternal();
}
this.close();
RocksDBException closeEx = this.closeEx;
if (closeEx != null) {
this.closeEx = null;
throw closeEx;
}
}
/**
* This is similar to {@link #closeE()} except that it
* silently ignores any errors.
*
* This will not fsync the WAL files.
* If syncing is required, the caller must first call {@link #syncWal()}
* or {@link #write(WriteOptions, WriteBatch)} using an empty write batch
* with {@link WriteOptions#setSync(boolean)} set to true.
*
* See also {@link #close()}.
*/
@Override
public void close() {
if (owningHandle_.compareAndSet(true, false)) {
protected void disposeInternal(boolean owningHandle) {
if (owningHandle) {
try {
closeDatabase(nativeHandle_);
} catch (final RocksDBException e) {
// silently ignore the error report
} catch (RocksDBException e) {
closeEx = e;
} finally {
disposeInternal();
super.disposeInternal(true);
}
}
}

View File

@ -65,8 +65,10 @@ public abstract class RocksCallbackObject extends
* Deletes underlying C++ native callback object pointer
*/
@Override
protected void disposeInternal() {
disposeInternal(nativeHandle_);
protected void disposeInternal(boolean owningHandle) {
if (owningHandle) {
disposeInternal(nativeHandle_);
}
}
private native void disposeInternal(final long handle);

View File

@ -39,6 +39,8 @@ public class RocksDB extends RocksObject {
private final List<ColumnFamilyHandle> ownedColumnFamilyHandles = new ArrayList<>();
protected RocksDBException closeEx = null;
/**
* Loads the necessary library files.
* Calling this method twice will have no effect.
@ -607,45 +609,28 @@ public class RocksDB extends RocksObject {
* @throws RocksDBException if an error occurs whilst closing.
*/
public void closeE() throws RocksDBException {
for (final ColumnFamilyHandle columnFamilyHandle : ownedColumnFamilyHandles) {
columnFamilyHandle.close();
}
ownedColumnFamilyHandles.clear();
if (owningHandle_.compareAndSet(true, false)) {
try {
closeDatabase(nativeHandle_);
} finally {
disposeInternal();
}
this.close();
RocksDBException closeEx = this.closeEx;
if (closeEx != null) {
this.closeEx = null;
throw closeEx;
}
}
/**
* This is similar to {@link #closeE()} except that it
* silently ignores any errors.
*
* This will not fsync the WAL files.
* If syncing is required, the caller must first call {@link #syncWal()}
* or {@link #write(WriteOptions, WriteBatch)} using an empty write batch
* with {@link WriteOptions#setSync(boolean)} set to true.
*
* See also {@link #close()}.
*/
@Override
public void close() {
protected void disposeInternal(boolean owningHandle) {
for (final ColumnFamilyHandle columnFamilyHandle : ownedColumnFamilyHandles) {
columnFamilyHandle.close();
}
ownedColumnFamilyHandles.clear();
if (owningHandle_.compareAndSet(true, false)) {
if (owningHandle) {
try {
closeDatabase(nativeHandle_);
} catch (final RocksDBException e) {
// silently ignore the error report
} catch (RocksDBException e) {
closeEx = e;
} finally {
disposeInternal();
super.disposeInternal(true);
}
}
}

View File

@ -5,6 +5,9 @@
package org.rocksdb;
import io.netty5.buffer.api.Drop;
import io.netty5.buffer.api.Owned;
/**
* RocksMutableObject is an implementation of {@link AbstractNativeReference}
* whose reference to the underlying native C++ object can change.
@ -13,7 +16,21 @@ package org.rocksdb;
* has synchronization overheads and introduces complexity. Instead it is
* recommended to use {@link RocksObject} where possible.</p>
*/
public abstract class RocksMutableObject extends AbstractNativeReference {
public abstract class RocksMutableObject extends AbstractNativeReference<RocksMutableObject> {
private static final Drop<RocksMutableObject> DROP = new Drop<RocksMutableObject>() {
@Override public void drop(RocksMutableObject obj) {
obj.doDrop();
}
@Override public Drop<RocksMutableObject> fork() {
return this;
}
@Override public void attach(RocksMutableObject obj) {
}
};
/**
* An mutable reference to the value of the C++ pointer pointing to some
@ -23,9 +40,11 @@ public abstract class RocksMutableObject extends AbstractNativeReference {
private boolean owningHandle_;
protected RocksMutableObject() {
super(DROP);
}
protected RocksMutableObject(final long nativeHandle) {
super(DROP);
this.nativeHandle_ = nativeHandle;
this.owningHandle_ = true;
}
@ -56,7 +75,7 @@ public abstract class RocksMutableObject extends AbstractNativeReference {
@Override
protected synchronized boolean isOwningHandle() {
return this.owningHandle_;
return this.owningHandle_ && isAccessible();
}
/**
@ -70,12 +89,10 @@ public abstract class RocksMutableObject extends AbstractNativeReference {
return this.nativeHandle_;
}
@Override
public synchronized final void close() {
private synchronized void doDrop() {
if (isOwningHandle()) {
disposeInternal();
this.owningHandle_ = false;
this.nativeHandle_ = 0;
nativeHandle_ = 0;
}
}

View File

@ -33,8 +33,10 @@ public abstract class RocksObject extends AbstractImmutableNativeReference {
* Deletes underlying C++ object pointer.
*/
@Override
protected void disposeInternal() {
disposeInternal(nativeHandle_);
protected void disposeInternal(boolean owningHandle) {
if (owningHandle) {
disposeInternal(nativeHandle_);
}
}
protected abstract void disposeInternal(final long handle);

View File

@ -117,35 +117,23 @@ public class TransactionDB extends RocksDB
* @throws RocksDBException if an error occurs whilst closing.
*/
public void closeE() throws RocksDBException {
if (owningHandle_.compareAndSet(true, false)) {
try {
closeDatabase(nativeHandle_);
} finally {
disposeInternal();
}
this.close();
RocksDBException closeEx = this.closeEx;
if (closeEx != null) {
this.closeEx = null;
throw closeEx;
}
}
/**
* This is similar to {@link #closeE()} except that it
* silently ignores any errors.
*
* This will not fsync the WAL files.
* If syncing is required, the caller must first call {@link #syncWal()}
* or {@link #write(WriteOptions, WriteBatch)} using an empty write batch
* with {@link WriteOptions#setSync(boolean)} set to true.
*
* See also {@link #close()}.
*/
@Override
public void close() {
if (owningHandle_.compareAndSet(true, false)) {
protected void disposeInternal(boolean owningHandle) {
if (owningHandle) {
try {
closeDatabase(nativeHandle_);
} catch (final RocksDBException e) {
// silently ignore the error report
} catch (RocksDBException e) {
closeEx = e;
} finally {
disposeInternal();
super.disposeInternal(true);
}
}
}

View File

@ -155,35 +155,23 @@ public class TtlDB extends RocksDB {
* @throws RocksDBException if an error occurs whilst closing.
*/
public void closeE() throws RocksDBException {
if (owningHandle_.compareAndSet(true, false)) {
try {
closeDatabase(nativeHandle_);
} finally {
disposeInternal();
}
this.close();
RocksDBException closeEx = this.closeEx;
if (closeEx != null) {
this.closeEx = null;
throw closeEx;
}
}
/**
* <p>Close the TtlDB instance and release resource.</p>
*
*
* This will not fsync the WAL files.
* If syncing is required, the caller must first call {@link #syncWal()}
* or {@link #write(WriteOptions, WriteBatch)} using an empty write batch
* with {@link WriteOptions#setSync(boolean)} set to true.
*
* See also {@link #close()}.
*/
@Override
public void close() {
if (owningHandle_.compareAndSet(true, false)) {
protected void disposeInternal(boolean owningHandle) {
if (owningHandle) {
try {
closeDatabase(nativeHandle_);
} catch (final RocksDBException e) {
// silently ignore the error report
} catch (RocksDBException e) {
closeEx = e;
} finally {
disposeInternal();
super.disposeInternal(true);
}
}
}

View File

@ -93,10 +93,8 @@ public class WBWIRocksIterator
}
}
@Override
public void close() {
@Override protected void disposeInternal(boolean owningHandle) {
entry.close();
super.close();
}
/**