fix(education): lock collection migration adoption
This commit is contained in:
@@ -1,6 +1,13 @@
|
|||||||
-- EDU-010: current-tenant manual Question Collection authoring lifecycle.
|
-- EDU-010: current-tenant manual Question Collection authoring lifecycle.
|
||||||
-- JAVA_READ application authority is enforced in Java; database guards protect direct mutation.
|
-- JAVA_READ application authority is enforced in Java; database guards protect direct mutation.
|
||||||
|
|
||||||
|
-- Prevent concurrent collection/membership/question mutation across adoption validation,
|
||||||
|
-- backfill, and trigger installation while retaining ordinary reads.
|
||||||
|
LOCK TABLE education_question_collection,
|
||||||
|
education_question_collection_question,
|
||||||
|
education_question
|
||||||
|
IN SHARE ROW EXCLUSIVE MODE;
|
||||||
|
|
||||||
ALTER TABLE education_question_collection
|
ALTER TABLE education_question_collection
|
||||||
ADD COLUMN publication_status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE',
|
ADD COLUMN publication_status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE',
|
||||||
ADD COLUMN authoring_version INTEGER NOT NULL DEFAULT 0,
|
ADD COLUMN authoring_version INTEGER NOT NULL DEFAULT 0,
|
||||||
|
|||||||
@@ -675,6 +675,33 @@ class EducationFlywayMigrationIntegrationTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldUseMigrationLocksThatBlockMembershipAndQuestionWrites() throws SQLException {
|
||||||
|
String schema = createSchema("collection_lock_modes");
|
||||||
|
configureFlyway(schema, false).target("4100").load().migrate();
|
||||||
|
try (Connection locker = DriverManager.getConnection(jdbcUrl(schema), USER, PASSWORD);
|
||||||
|
Connection writer = DriverManager.getConnection(jdbcUrl(schema), USER, PASSWORD)) {
|
||||||
|
locker.setAutoCommit(false);
|
||||||
|
try (var statement = locker.createStatement()) {
|
||||||
|
statement.execute("LOCK TABLE education_question_collection, education_question_collection_question, education_question IN SHARE ROW EXCLUSIVE MODE");
|
||||||
|
}
|
||||||
|
assertThat(queryLong(schema, """
|
||||||
|
SELECT count(*) FROM pg_locks lock
|
||||||
|
JOIN pg_class relation ON relation.oid=lock.relation
|
||||||
|
WHERE lock.pid<>pg_backend_pid() AND lock.mode='ShareRowExclusiveLock' AND lock.granted
|
||||||
|
AND relation.relname IN ('education_question_collection','education_question_collection_question','education_question')
|
||||||
|
""")).isEqualTo(3L);
|
||||||
|
try (var statement = writer.createStatement()) {
|
||||||
|
statement.execute("SET lock_timeout='250ms'");
|
||||||
|
assertThatThrownBy(() -> statement.execute("DELETE FROM education_question_collection_question WHERE false"))
|
||||||
|
.hasMessageContaining("lock timeout");
|
||||||
|
assertThatThrownBy(() -> statement.execute("UPDATE education_question SET deleted=deleted WHERE false"))
|
||||||
|
.hasMessageContaining("lock timeout");
|
||||||
|
}
|
||||||
|
locker.rollback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldFailV4110ForHistoricalCollectionEntryDivergence() throws SQLException {
|
void shouldFailV4110ForHistoricalCollectionEntryDivergence() throws SQLException {
|
||||||
String schema = createSchema("collection_entry_divergence");
|
String schema = createSchema("collection_entry_divergence");
|
||||||
|
|||||||
Reference in New Issue
Block a user