1 // Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2 //  This source code is licensed under both the GPLv2 (found in the
3 //  COPYING file in the root directory) and Apache 2.0 License
4 //  (found in the LICENSE.Apache file in the root directory).
5 
6 package org.rocksdb;
7 
8 import java.util.Arrays;
9 import java.util.Objects;
10 
11 /**
12  * ColumnFamilyHandle class to hold handles to underlying rocksdb
13  * ColumnFamily Pointers.
14  */
15 public class ColumnFamilyHandle extends RocksObject {
16   /**
17    * Constructs column family Java object, which operates on underlying native object.
18    *
19    * @param rocksDB db instance associated with this column family
20    * @param nativeHandle native handle to underlying native ColumnFamily object
21    */
ColumnFamilyHandle(final RocksDB rocksDB, final long nativeHandle)22   ColumnFamilyHandle(final RocksDB rocksDB,
23       final long nativeHandle) {
24     super(nativeHandle);
25     // rocksDB must point to a valid RocksDB instance;
26     assert(rocksDB != null);
27     // ColumnFamilyHandle must hold a reference to the related RocksDB instance
28     // to guarantee that while a GC cycle starts ColumnFamilyHandle instances
29     // are freed prior to RocksDB instances.
30     this.rocksDB_ = rocksDB;
31   }
32 
33   /**
34    * Constructor called only from JNI.
35    *
36    * NOTE: we are producing an additional Java Object here to represent the underlying native C++
37    * ColumnFamilyHandle object. The underlying object is not owned by ourselves. The Java API user
38    * likely already had a ColumnFamilyHandle Java object which owns the underlying C++ object, as
39    * they will have been presented it when they opened the database or added a Column Family.
40    *
41    *
42    * TODO(AR) - Potentially a better design would be to cache the active Java Column Family Objects
43    * in RocksDB, and return the same Java Object instead of instantiating a new one here. This could
44    * also help us to improve the Java API semantics for Java users. See for example
45    * https://github.com/facebook/rocksdb/issues/2687.
46    *
47    * @param nativeHandle native handle to the column family.
48    */
ColumnFamilyHandle(final long nativeHandle)49   ColumnFamilyHandle(final long nativeHandle) {
50     super(nativeHandle);
51     rocksDB_ = null;
52     disOwnNativeHandle();
53   }
54 
55   /**
56    * Gets the name of the Column Family.
57    *
58    * @return The name of the Column Family.
59    *
60    * @throws RocksDBException if an error occurs whilst retrieving the name.
61    */
getName()62   public byte[] getName() throws RocksDBException {
63     assert(isOwningHandle() || isDefaultColumnFamily());
64     return getName(nativeHandle_);
65   }
66 
67   /**
68    * Gets the ID of the Column Family.
69    *
70    * @return the ID of the Column Family.
71    */
getID()72   public int getID() {
73     assert(isOwningHandle() || isDefaultColumnFamily());
74     return getID(nativeHandle_);
75   }
76 
77   /**
78    * Gets the up-to-date descriptor of the column family
79    * associated with this handle. Since it fills "*desc" with the up-to-date
80    * information, this call might internally lock and release DB mutex to
81    * access the up-to-date CF options. In addition, all the pointer-typed
82    * options cannot be referenced any longer than the original options exist.
83    *
84    * Note that this function is not supported in RocksDBLite.
85    *
86    * @return the up-to-date descriptor.
87    *
88    * @throws RocksDBException if an error occurs whilst retrieving the
89    *     descriptor.
90    */
getDescriptor()91   public ColumnFamilyDescriptor getDescriptor() throws RocksDBException {
92     assert(isOwningHandle() || isDefaultColumnFamily());
93     return getDescriptor(nativeHandle_);
94   }
95 
96   @Override
equals(final Object o)97   public boolean equals(final Object o) {
98     if (this == o) {
99       return true;
100     }
101     if (o == null || getClass() != o.getClass()) {
102       return false;
103     }
104 
105     final ColumnFamilyHandle that = (ColumnFamilyHandle) o;
106     try {
107       return rocksDB_.nativeHandle_ == that.rocksDB_.nativeHandle_ &&
108           getID() == that.getID() &&
109           Arrays.equals(getName(), that.getName());
110     } catch (RocksDBException e) {
111       throw new RuntimeException("Cannot compare column family handles", e);
112     }
113   }
114 
115   @Override
hashCode()116   public int hashCode() {
117     try {
118       int result = Objects.hash(getID(), rocksDB_.nativeHandle_);
119       result = 31 * result + Arrays.hashCode(getName());
120       return result;
121     } catch (RocksDBException e) {
122       throw new RuntimeException("Cannot calculate hash code of column family handle", e);
123     }
124   }
125 
isDefaultColumnFamily()126   protected boolean isDefaultColumnFamily() {
127     return nativeHandle_ == rocksDB_.getDefaultColumnFamily().nativeHandle_;
128   }
129 
130   /**
131    * <p>Deletes underlying C++ iterator pointer.</p>
132    *
133    * <p>Note: the underlying handle can only be safely deleted if the RocksDB
134    * instance related to a certain ColumnFamilyHandle is still valid and
135    * initialized. Therefore {@code disposeInternal()} checks if the RocksDB is
136    * initialized before freeing the native handle.</p>
137    */
138   @Override
disposeInternal()139   protected void disposeInternal() {
140     if(rocksDB_.isOwningHandle()) {
141       disposeInternal(nativeHandle_);
142     }
143   }
144 
getName(final long handle)145   private native byte[] getName(final long handle) throws RocksDBException;
getID(final long handle)146   private native int getID(final long handle);
getDescriptor(final long handle)147   private native ColumnFamilyDescriptor getDescriptor(final long handle) throws RocksDBException;
disposeInternal(final long handle)148   @Override protected final native void disposeInternal(final long handle);
149 
150   private final RocksDB rocksDB_;
151 }
152