Skip to content

Commit

Permalink
ledger-on-memory: Lock on read. (digital-asset#12715)
Browse files Browse the repository at this point in the history
* ledger-on-memory: Lock on read.

I hoped we could get away with not doing this, but no such luck.
Scala 2.13.8 makes the problem visible, but it was always there.

CHANGELOG_BEGIN
CHANGELOG_END

* ledger-on-memory: Handle exceptions on read.
  • Loading branch information
SamirTalwar authored Feb 2, 2022
1 parent a29d2a7 commit 34287f6
Showing 1 changed file with 19 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,24 @@ import scala.collection.mutable
import scala.concurrent.{ExecutionContext, Future, blocking}

private[memory] class InMemoryState private (log: MutableLog, state: MutableState) {
// Ensure that mutable state does not change while reading.
// `StampedLock` supports many read locks, or one write lock.
private val lockCurrentState = new StampedLock()
@volatile private var lastLogEntryIndex = 0

def readLog[A](action: ImmutableLog => A): A =
action(log) // `log` is mutable, but the interface is immutable

def newHeadSinceLastWrite(): Int = lastLogEntryIndex

def readLog[A](action: ImmutableLog => A): A = {
val stamp = blocking {
lockCurrentState.readLock()
}
try {
action(log) // `log` is mutable, but the interface is immutable
} finally {
lockCurrentState.unlock(stamp)
}
}

def write[A](action: (MutableLog, MutableState) => Future[A])(implicit
executionContext: ExecutionContext
): Future[A] =
Expand All @@ -47,12 +57,10 @@ object InMemoryState {
type MutableState = mutable.Map[Raw.StateKey, Raw.Envelope] with ImmutableState

// The first element will never be read because begin offsets are exclusive.
private val Beginning =
LedgerRecord(Offset.beforeBegin, Raw.LogEntryId.empty, Raw.Envelope.empty)

def empty =
new InMemoryState(
log = mutable.ArrayBuffer(Beginning),
state = mutable.Map.empty,
)
private val Beginning = LedgerRecord(Offset.beforeBegin, Raw.LogEntryId.empty, Raw.Envelope.empty)

def empty = new InMemoryState(
log = mutable.ArrayBuffer(Beginning),
state = mutable.Map.empty,
)
}

0 comments on commit 34287f6

Please sign in to comment.