fix(mocks): fold the audit window, and append MPE_AUDIT under its lock
Two review findings on this branch. - editors/restore.js spread every audit row for the load into Math.min(...). MPE_AUDIT is append-only, so a long-lived estate would eventually exceed the engine's argument limit and the RangeError would surface as a failed restore of a perfectly restorable load. Folded into a reduce with an Infinity seed. - auditors/postdata.js appended to MPE_AUDIT as a read-modify-write outside any lock. postdata.sas locks the table it writes - MPE_REVIEW around its proc append, MPE_SUBMIT around its update - so the audit append now takes the MPE_AUDIT lock around a fresh read, the concat and the save, rather than reading the table up front and saving a copy that may be missing another approval's rows. 53 mock tests pass (node --test sas/mocks/test/).
This commit is contained in:
1 parent
1a60c689f4
commit
5ecc7bebec
2 files changed
+25
-9
No files matched your search
@@ -728,11 +728,10 @@ if (action === 'SHOW_DIFFS') {
|
||||
.join('|')
|
||||
)
|
||||
|
||||
const auditTable = mpeLoadTableData('MPE_AUDIT') || {
|
||||
name: 'MPE_AUDIT',
|
||||
columns: [],
|
||||
rows: []
|
||||
}
|
||||
// The rows this approval adds. They are appended to the table under the
|
||||
// MPE_REVIEW lock below, not to a copy read here: two approvals landing
|
||||
// together would otherwise each save a table without the other's rows.
|
||||
const pending = []
|
||||
|
||||
const entry = (row, moveType, column, oldVal, newVal, isPk, isDiff) => {
|
||||
const type = column.type === 'N' ? 'N' : 'C'
|
||||
@@ -759,7 +758,7 @@ if (action === 'SHOW_DIFFS') {
|
||||
}
|
||||
put('OLDVAL', oldVal)
|
||||
put('NEWVAL', newVal)
|
||||
auditTable.rows.push(auditRow)
|
||||
pending.push(auditRow)
|
||||
}
|
||||
|
||||
const isKey = (name) =>
|
||||
@@ -792,7 +791,23 @@ if (action === 'SHOW_DIFFS') {
|
||||
}
|
||||
}
|
||||
|
||||
if (auditTable.rows.length) saveTableToLib('MPE_AUDIT', auditTable)
|
||||
if (pending.length) {
|
||||
// postdata.sas locks the table it appends to (MPE_REVIEW around its
|
||||
// proc append, MPE_SUBMIT around its update), so the audit append takes
|
||||
// the MPE_AUDIT lock rather than borrowing the review one.
|
||||
lockControl('MPE_AUDIT', loadRef + ' Approval')
|
||||
try {
|
||||
const fresh = mpeLoadTableData('MPE_AUDIT') || {
|
||||
name: 'MPE_AUDIT',
|
||||
columns: [],
|
||||
rows: []
|
||||
}
|
||||
fresh.rows = (fresh.rows || []).concat(pending)
|
||||
saveTableToLib('MPE_AUDIT', fresh)
|
||||
} finally {
|
||||
unlockControl('MPE_AUDIT')
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
// an audit failure must not undo an approval that already landed
|
||||
console.log('Error writing MPE_AUDIT: ' + err.message)
|
||||
|
||||
@@ -115,8 +115,9 @@ try {
|
||||
// The load's timestamp, then every change to that table from then on: the
|
||||
// change to revert plus all subsequent ones.
|
||||
|
||||
const stamp = Math.min(
|
||||
...mine.map((row) => Number(colVal(row, 'PROCESSED_DTTM')))
|
||||
const stamp = mine.reduce(
|
||||
(min, row) => Math.min(min, Number(colVal(row, 'PROCESSED_DTTM'))),
|
||||
Infinity
|
||||
)
|
||||
const window = all.filter(
|
||||
(row) =>
|
||||
|
||||
Reference in new issue
Block a user