Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only close cursor when it wasn't closed for us #159

Merged
merged 1 commit into from
Feb 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 37 additions & 2 deletions src/LightningDB.Tests/CursorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,6 @@ public void CursorShouldPutValues()
_env.RunCursorScenario((tx, _, c) =>
{
PopulateCursorValues(c);
c.Dispose();
//TODO evaluate how not to require this Dispose likely due to #155
var result = tx.Commit();
Assert.Equal(MDBResultCode.Success, result);
});
Expand Down Expand Up @@ -362,4 +360,41 @@ public void ShouldDeleteDuplicates()
Assert.Equal(MDBResultCode.NotFound, result);
}, DatabaseOpenFlags.DuplicatesFixed | DatabaseOpenFlags.Create);
}

[Fact]
public void CanPutBatchesViaCursorIssue155()
{
static LightningDatabase OpenDatabase(LightningEnvironment environment)
{
using var tx = environment.BeginTransaction();
var db = tx.OpenDatabase(configuration: new DatabaseConfiguration { Flags = DatabaseOpenFlags.Create });
tx.Commit();
return db;
}

void ReproduceCoreIteration(LightningEnvironment environment, LightningDatabase db)
{
using var tx = environment.BeginTransaction(); //auto-disposed at end of scope
using var cursor = tx.CreateCursor(db); //auto-disposed at end of scope

var guid = Guid.NewGuid().ToString();
var guidBytes = UTF8.GetBytes(guid);

_ = cursor.Put(
guidBytes,
guidBytes,
CursorPutOptions.None
);

tx.Commit().ThrowOnError();
}

using var db = OpenDatabase(_env);

for (var i = 0; i < 5000; i++)
{
ReproduceCoreIteration(_env, db);
}
Assert.True(true, "Code would be unreachable otherwise.");
}
}
10 changes: 7 additions & 3 deletions src/LightningDB/LightningCursor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ internal LightningCursor(LightningDatabase db, LightningTransaction txn)
mdb_cursor_open(txn.Handle(), db.Handle(), out _handle).ThrowOnError();

Transaction = txn;
Transaction.ShouldCloseCursor = true;
Transaction.Disposing += Dispose;
}

Expand Down Expand Up @@ -503,14 +504,17 @@ public MDBResultCode Renew(LightningTransaction txn)
/// <param name="disposing">True if called from Dispose.</param>
private void Dispose(bool disposing)
{
if (_handle == 0)
if (_handle == default)
return;

if (!disposing)
throw new InvalidOperationException("The LightningCursor was not disposed and cannot be reliably dealt with from the finalizer");

mdb_cursor_close(_handle);
_handle = 0;
if (Transaction.ShouldCloseCursor)
{
mdb_cursor_close(_handle);
}
_handle = default;

Transaction.Disposing -= Dispose;

Expand Down
1 change: 1 addition & 0 deletions src/LightningDB/LightningDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ public Stats DatabaseStats
public MDBResultCode Drop(LightningTransaction transaction)
{
var result = mdb_drop(transaction.Handle(), _handle, true);
_transaction.ShouldCloseCursor = false;
IsOpened = false;
_handle = default;
return result;
Expand Down
3 changes: 3 additions & 0 deletions src/LightningDB/LightningTransaction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ private void OnParentStateChanging(LightningTransactionState state)

public event Action Disposing;
private event Action<LightningTransactionState> StateChanging;

internal bool ShouldCloseCursor { get; set; }

/// <summary>
/// Current transaction state.
Expand Down Expand Up @@ -295,6 +297,7 @@ public MDBResultCode Renew()
public MDBResultCode Commit()
{
State = LightningTransactionState.Committed;
ShouldCloseCursor = false;
StateChanging?.Invoke(State);
return mdb_txn_commit(_handle);
}
Expand Down