Skip to content

Commit 633ec26

Browse files
committed
Disable allowUnconfirmed where we don’t want to support it (yet)
We want to enable `allowUnconfirmed` for puts and deletes in implicit transactions. This means disabling `allowUnconfirmed` for: * anything in an explicit transaction. The API for explicit transactions inherits the `allowUnconfirmed` option, so theoretically we could make all of the writes in a transaction be unconfirmed, and therefore the commit would be unconfirmed. We may want to support this in the future * `setAlarm`. We may want to support this in the future. * `deleteAll`. This is probably difficult to support. There is an edge case where multi-put creates its own explicit transaction that will disable `allowUnconfirmed`. This should probably be fixed to use an implicit transaction instead. When we override the `allowUnconfirmed` option to disable it, we log a message. I plan to look at these messages to see if they’re ever actually logged.
1 parent 7a0750b commit 633ec26

File tree

1 file changed

+37
-0
lines changed

1 file changed

+37
-0
lines changed

src/workerd/io/actor-sqlite.c++

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ static bool willFireEarlier(kj::Maybe<kj::Date> alarm1, kj::Maybe<kj::Date> alar
2525
return alarm1.orDefault(kj::maxValue) < alarm2.orDefault(kj::maxValue);
2626
}
2727

28+
// Set options.allowUnconfirmed to false and log a reason why.
29+
void disableAllowUnconfirmed(ActorCacheOps::WriteOptions& options, kj::StringPtr reason) {
30+
if (options.allowUnconfirmed) {
31+
KJ_LOG(WARNING, "NOSENTRY allowUnconfirmed disabled", reason);
32+
options.allowUnconfirmed = false;
33+
}
34+
}
35+
2836
} // namespace
2937

3038
ActorSqlite::ActorSqlite(kj::Own<SqliteDatabase> dbParam,
@@ -471,6 +479,9 @@ kj::OneOf<ActorCacheOps::GetResultList, kj::Promise<ActorCacheOps::GetResultList
471479

472480
kj::Maybe<kj::Promise<void>> ActorSqlite::put(Key key, Value value, WriteOptions options) {
473481
requireNotBroken();
482+
if (currentTxn.is<ExplicitTxn*>()) {
483+
disableAllowUnconfirmed(options, "single put is using an already-existing ExplicitTxn");
484+
}
474485
kv.put(key, value, {.allowUnconfirmed = options.allowUnconfirmed});
475486
return kj::none;
476487
}
@@ -482,10 +493,19 @@ kj::Maybe<kj::Promise<void>> ActorSqlite::put(kj::Array<KeyValuePair> pairs, Wri
482493
if (currentTxn.is<NoTxn>()) {
483494
// If we are not in a transcation, let's use an ExplicitTxn, which should rollback automatically
484495
// if some put fails.
496+
497+
// TODO(someday) this should really start an ImplicitTxn, which has the advantage of
498+
// supporting allowUnconfirmed.
499+
disableAllowUnconfirmed(options, "multi put will create an ExplicitTxn");
500+
485501
auto txn = startTransaction();
486502
txn->put(kj::mv(pairs), options);
487503
txn->commit();
488504
} else {
505+
if (currentTxn.is<ExplicitTxn*>()) {
506+
disableAllowUnconfirmed(options, "multi put is using an already-existing ExplicitTxn");
507+
}
508+
489509
// If we are in a transaction, let's just set a SAVEPOINT that we can rollback to if needed.
490510
db->run(
491511
{.regulator = SqliteDatabase::TRUSTED}, kj::str("SAVEPOINT _cf_put_multiple_savepoint"));
@@ -516,12 +536,20 @@ kj::Maybe<kj::Promise<void>> ActorSqlite::put(kj::Array<KeyValuePair> pairs, Wri
516536
kj::OneOf<bool, kj::Promise<bool>> ActorSqlite::delete_(Key key, WriteOptions options) {
517537
requireNotBroken();
518538

539+
if (currentTxn.is<ExplicitTxn*>()) {
540+
disableAllowUnconfirmed(options, "single delete is using an already-existing ExplicitTxn");
541+
}
542+
519543
return kv.delete_(key, {.allowUnconfirmed = options.allowUnconfirmed});
520544
}
521545

522546
kj::OneOf<uint, kj::Promise<uint>> ActorSqlite::delete_(kj::Array<Key> keys, WriteOptions options) {
523547
requireNotBroken();
524548

549+
if (currentTxn.is<ExplicitTxn*>()) {
550+
disableAllowUnconfirmed(options, "multi delete put is using an already-existing ExplicitTxn");
551+
}
552+
525553
uint count = 0;
526554
for (auto& key: keys) {
527555
count += kv.delete_(key, {.allowUnconfirmed = options.allowUnconfirmed});
@@ -533,6 +561,8 @@ kj::Maybe<kj::Promise<void>> ActorSqlite::setAlarm(
533561
kj::Maybe<kj::Date> newAlarmTime, WriteOptions options) {
534562
requireNotBroken();
535563

564+
disableAllowUnconfirmed(options, "setAlarm is not supported");
565+
536566
// TODO(someday): When deleting alarm data in an otherwise empty database, clear the database to
537567
// free up resources?
538568

@@ -556,6 +586,8 @@ kj::Own<ActorCacheInterface::Transaction> ActorSqlite::startTransaction() {
556586
ActorCacheInterface::DeleteAllResults ActorSqlite::deleteAll(WriteOptions options) {
557587
requireNotBroken();
558588

589+
disableAllowUnconfirmed(options, "deleteAll is not supported");
590+
559591
// kv.deleteAll() clears the database, so we need to save and possibly restore alarm state in
560592
// the metadata table, to try to match the behavior of ActorCache, which preserves the set alarm
561593
// when running deleteAll().
@@ -827,22 +859,27 @@ kj::OneOf<ActorCacheOps::GetResultList, kj::Promise<ActorCacheOps::GetResultList
827859
}
828860
kj::Maybe<kj::Promise<void>> ActorSqlite::ExplicitTxn::put(
829861
Key key, Value value, WriteOptions options) {
862+
disableAllowUnconfirmed(options, "single put in ExplicitTxn not supported");
830863
return actorSqlite.put(kj::mv(key), kj::mv(value), options);
831864
}
832865
kj::Maybe<kj::Promise<void>> ActorSqlite::ExplicitTxn::put(
833866
kj::Array<KeyValuePair> pairs, WriteOptions options) {
867+
disableAllowUnconfirmed(options, "multi put in ExplicitTxn not supported");
834868
return actorSqlite.put(kj::mv(pairs), options);
835869
}
836870
kj::OneOf<bool, kj::Promise<bool>> ActorSqlite::ExplicitTxn::delete_(
837871
Key key, WriteOptions options) {
872+
disableAllowUnconfirmed(options, "single delete in ExplicitTxn not supported");
838873
return actorSqlite.delete_(kj::mv(key), options);
839874
}
840875
kj::OneOf<uint, kj::Promise<uint>> ActorSqlite::ExplicitTxn::delete_(
841876
kj::Array<Key> keys, WriteOptions options) {
877+
disableAllowUnconfirmed(options, "multi delete in ExplicitTxn not supported");
842878
return actorSqlite.delete_(kj::mv(keys), options);
843879
}
844880
kj::Maybe<kj::Promise<void>> ActorSqlite::ExplicitTxn::setAlarm(
845881
kj::Maybe<kj::Date> newAlarmTime, WriteOptions options) {
882+
disableAllowUnconfirmed(options, "setAlarm in ExplicitTxn not supported");
846883
return actorSqlite.setAlarm(newAlarmTime, options);
847884
}
848885

0 commit comments

Comments
 (0)