4545import org .lmdbjava .Library .MDB_stat ;
4646
4747/**
48- * LMDB environment.
48+ * An LMDB environment that includes one or more databases ({@link Dbi}s). The {@link Env} manages
49+ * the transactions and databases. An {@link Env} can only have one concurrent write transaction but
50+ * supports multiple concurrent read transactions.
51+ *
52+ * <p><strong>WARNING</strong>: LMDBJava's and LMDB's performance comes from their low-level memory
53+ * access, but this requires that you strictly adhere to the various contracts set out when using
54+ * environments, databases, transactions, and cursors. Incorrect use of LMDBJava can lead to
55+ * segmentation faults that can crash your application.
56+ *
57+ * <p>By default, LMDBJava performs some checks, for example, checking that the {@link Env} is not
58+ * closed when opening a transaction. It is possible, however, for race conditions to occur if you
59+ * close the {@link Env} after one of these checks has been performed and before the transaction is
60+ * opened. Note, these checks can be disabled by setting the {@link #DISABLE_CHECKS_PROP} system
61+ * property to {@code true}. This may be beneficial in performance-critical applications.
62+ *
63+ * <p>{@link Builder#setSafeClose()} can also be used to add additional checks that ensure the
64+ * {@link Env} is not closed while transactions/cursors are in use.
65+ *
66+ * <p>It is the responsibility of the user to ensure that the {@link Env} is not closed while
67+ * transactions or cursors are in use.
4968 *
5069 * @param <T> buffer type
5170 */
@@ -79,6 +98,7 @@ public final class Env<T> implements AutoCloseable {
7998 /** True if this Env has been created on the basis of only ever being used by a single thread. */
8099 private final boolean isSingleThreaded ;
81100
101+ /** If true, close will be prevented if there are open txns/cursors. */
82102 private final boolean safeClose ;
83103
84104 private Env (
@@ -450,10 +470,11 @@ boolean isSafeClose() {
450470 }
451471
452472 /**
453- * Returns a builder for creating and opening a {@link Dbi} instance in this {@link Env}.
473+ * Returns a builder for creating and opening a {@link Dbi} instance in this {@link Env}. This
474+ * method is used for both opening an existing database or creating a new one.
454475 *
455- * <p>The flag {@link DbiFlags#MDB_CREATE} needs to be set on the builder if you need to create a
456- * new database before opening it.
476+ * <p>The flag {@link DbiFlags#MDB_CREATE} needs to be set on the builder if the database does not
477+ * already exist, and you need to create it before opening it.
457478 *
458479 * @return A new builder instance for creating/opening a {@link Dbi}.
459480 */
@@ -641,6 +662,9 @@ public void sync(final boolean force) {
641662 * @return a transaction (never null)
642663 * @deprecated Instead use {@link Env#txn(Txn, TxnFlagSet)}
643664 * <p>Obtain a transaction with the requested parent and flags.
665+ * <p>Must not race a concurrent {@link #close()} on another thread: the closed-check and the
666+ * native transaction start are not atomic, so a close occurring between them can crash the
667+ * JVM (see {@link #close()}).
644668 */
645669 @ Deprecated
646670 public Txn <T > txn (final Txn <T > parent , final TxnFlags ... flags ) {
@@ -649,9 +673,18 @@ public Txn<T> txn(final Txn<T> parent, final TxnFlags... flags) {
649673 }
650674
651675 /**
652- * Obtain a transaction with the requested parent and flags.
676+ * Obtain a read-write transaction with the requested parent and flags.
653677 *
654- * @param parent parent transaction (may be null if no parent)
678+ * <p>Must not race a concurrent {@link #close()} on another thread: the closed-check and the
679+ * native transaction start are not atomic, so a close occurring between them can crash the JVM
680+ * (see {@link #close()}).
681+ *
682+ * <p>When using a parent transaction, any committed changes will only be visible to the parent
683+ * transaction and will only be fully committed to the {@link Dbi} if the root transaction is
684+ * committed. Aborting this transaction will not roll back changes already made by the parent
685+ * transaction.
686+ *
687+ * @param parent parent transaction (maybe null if no parent)
655688 * @return a transaction (never null)
656689 */
657690 public Txn <T > txn (final Txn <T > parent ) {
@@ -662,11 +695,25 @@ public Txn<T> txn(final Txn<T> parent) {
662695 /**
663696 * Obtain a transaction with the requested parent and flags.
664697 *
665- * @param parent parent transaction (may be null if no parent)
698+ * <p>If you want a read-write transaction, you can instead call {@link #txn(Txn)}. To obtain a
699+ * read-only transaction, ensure {@link TxnFlags#MDB_RDONLY_TXN} is present in the {@link
700+ * TxnFlagSet}.
701+ *
702+ * <p>Must not race a concurrent {@link #close()} on another thread: the closed-check and the
703+ * native transaction start are not atomic, so a close occurring between them can crash the JVM
704+ * (see {@link #close()}).
705+ *
706+ * <p>When using a parent transaction, any committed changes will only be visible to the parent
707+ * transaction and will only be fully committed to the {@link Dbi} if the root transaction is
708+ * committed. Aborting this transaction will not roll back changes already made by the parent
709+ * transaction.
710+ *
711+ * @param parent parent transaction (maybe null if no parent)
666712 * @param flags applicable flags (e.g. for a reusable, read-only transaction). If the set of flags
667- * is used frequently it is recommended to hold a static instance of the {@link TxnFlagSet}
713+ * is used frequently, it is recommended to hold a static instance of the {@link TxnFlagSet}
668714 * for re-use.
669715 * @return a transaction (never null)
716+ * @throws Env.AlreadyClosedException if this environment has already been closed.
670717 */
671718 public Txn <T > txn (final Txn <T > parent , final TxnFlagSet flags ) {
672719 checkNotClosed ();
@@ -676,7 +723,12 @@ public Txn<T> txn(final Txn<T> parent, final TxnFlagSet flags) {
676723 /**
677724 * Obtain a read-only transaction.
678725 *
726+ * <p>Must not race a concurrent {@link #close()} on another thread: the closed-check and the
727+ * native transaction start are not atomic, so a close occurring between them can crash the JVM
728+ * (see {@link #close()}).
729+ *
679730 * @return a read-only transaction
731+ * @throws Env.AlreadyClosedException if this environment has already been closed.
680732 */
681733 public Txn <T > txnRead () {
682734 checkNotClosed ();
@@ -686,7 +738,12 @@ public Txn<T> txnRead() {
686738 /**
687739 * Obtain a read-write transaction.
688740 *
741+ * <p>Must not race a concurrent {@link #close()} on another thread: the closed-check and the
742+ * native transaction start are not atomic, so a close occurring between them can crash the JVM
743+ * (see {@link #close()}).
744+ *
689745 * @return a read-write transaction
746+ * @throws Env.AlreadyClosedException if this environment has already been closed
690747 */
691748 public Txn <T > txnWrite () {
692749 checkNotClosed ();
@@ -1108,12 +1165,12 @@ public Builder<T> setSingleThreaded(final boolean singleThreaded) {
11081165 /**
11091166 * Enables the opt-in "safe close" for the resulting {@link Env}.
11101167 *
1111- * <p>When enabled, the environment tracks its live transactions and cursors so that closure of
1112- * the {@link Env} is prevented if transactions or cursors are active. This adds a small amount
1113- * of bookkeeping on transaction start/close; it is <strong>disabled by default</strong> so
1114- * applications that already manage their own threading (the common low-latency case) pay
1115- * nothing. When enabled, {@link Env#close()} will throw a {@link EnvInUseException} if
1116- * transactions or cursors are active.
1168+ * <p>When enabled, the environment tracks its live transactions and read-write cursors so that
1169+ * closure of the {@link Env} is prevented if transactions or cursors are active. This adds a
1170+ * small amount of bookkeeping on transaction start/close; it is <strong>disabled by
1171+ * default</strong> so applications that already manage their own threading (the common
1172+ * low-latency case) pay nothing. When enabled, {@link Env#close()} will throw a {@link
1173+ * EnvInUseException} if transactions or cursors are active.
11171174 *
11181175 * @return the builder
11191176 */
@@ -1125,12 +1182,12 @@ public Builder<T> setSafeClose() {
11251182 /**
11261183 * Enables the opt-in "safe close" for the resulting {@link Env}.
11271184 *
1128- * <p>When enabled, the environment tracks its live transactions and cursors so that closure of
1129- * the {@link Env} is prevented if transactions or cursors are active. This adds a small amount
1130- * of bookkeeping on transaction start/close; it is <strong>disabled by default</strong> so
1131- * applications that already manage their own threading (the common low-latency case) pay
1132- * nothing. When enabled, {@link Env#close()} will throw a {@link EnvInUseException} if
1133- * transactions or cursors are active.
1185+ * <p>When enabled, the environment tracks its live transactions and read-write cursors so that
1186+ * closure of the {@link Env} is prevented if transactions or cursors are active. This adds a
1187+ * small amount of bookkeeping on transaction start/close; it is <strong>disabled by
1188+ * default</strong> so applications that already manage their own threading (the common
1189+ * low-latency case) pay nothing. When enabled, {@link Env#close()} will throw a {@link
1190+ * EnvInUseException} if transactions or cursors are active.
11341191 *
11351192 * @param safeClose true to enable cursor/transaction tracking.
11361193 * @return the builder
0 commit comments