Skip to content

Commit 1c60bd0

Browse files
Lock acs_snapshot_data while writing
[ci] Signed-off-by: Robert Autenrieth <robert.autenrieth@digitalasset.com>
1 parent 2d72338 commit 1c60bd0

File tree

1 file changed

+22
-2
lines changed

1 file changed

+22
-2
lines changed

apps/scan/src/main/scala/org/lfdecentralizedtrust/splice/scan/store/AcsSnapshotStore.scala

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import com.digitalasset.canton.resource.DbStorage.Implicits.BuilderChain.toSQLAc
2525
import com.digitalasset.canton.topology.PartyId
2626
import com.digitalasset.canton.tracing.TraceContext
2727
import org.lfdecentralizedtrust.splice.store.events.SpliceCreatedEvent
28-
import slick.dbio.DBIOAction
28+
import slick.dbio.{DBIOAction, Effect, NoStream}
2929
import slick.jdbc.canton.ActionBasedSQLInterpolation.Implicits.actionBasedSQLInterpolationCanton
3030
import slick.jdbc.{GetResult, JdbcProfile}
3131

@@ -158,12 +158,32 @@ class AcsSnapshotStore(
158158
join creates_to_insert on inserted_rows.create_id = creates_to_insert.row_id
159159
having min(inserted_rows.row_id) is not null;
160160
""").toActionBuilder.asUpdate
161-
storage.update(statement, "insertNewSnapshot")
161+
storage.update(withExclusiveSnapshotDataLock(statement), "insertNewSnapshot")
162162
}.andThen { _ =>
163163
AcsSnapshotStore.PreventConcurrentSnapshotsSemaphore.release()
164164
}
165165
}
166166

167+
/** Wraps the given action in a transaction that holds an exclusive lock on the acs_snapshot_data table.
168+
*
169+
* Note: The acs_snapshot_data table must not have interleaved rows from two different acs snapshots.
170+
* In rare cases, it can happen that the application crashes while writing a snapshot, then
171+
* restarts and starts writing a different snapshot while the previous statement is still running.
172+
* The exclusive lock prevents this.
173+
* Once obtained, a lock is held for the remainder of the current transaction.
174+
* In case the application crashes while holding the lock, the server should close the connection
175+
* and abort the transaction as soon as it detects a disconnect.
176+
* See [[com.digitalasset.canton.platform.store.backend.postgresql.PostgresDataSourceConfig]] for our connection keepalive settings.
177+
* With default settings, the server should detect a dead connection within ~15sec.
178+
*/
179+
private def withExclusiveSnapshotDataLock[T, E <: Effect](
180+
action: DBIOAction[T, NoStream, E]
181+
): DBIOAction[T, NoStream, E & Effect.Write & Effect.Transactional] =
182+
(for {
183+
_ <- sqlu"LOCK TABLE acs_snapshot_data IN EXCLUSIVE MODE"
184+
result <- action
185+
} yield result).transactionally
186+
167187
def deleteSnapshot(
168188
snapshot: AcsSnapshot
169189
)(implicit

0 commit comments

Comments
 (0)