Skip to content

Commit f52eefa

Browse files
fix: Harmonize db sequences for tracker [DHIS2-21378] (#24208)
* fix: Harmonize db sequences for tracker [DHIS2-21378] * Fix relationshipitemid
1 parent 0e39697 commit f52eefa

11 files changed

Lines changed: 58 additions & 37 deletions

File tree

dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/program/hibernate/SingleEvent.hbm.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
<id name="id" column="eventid">
1010
<generator class="sequence">
11-
<param name="sequence_name">programstageinstance_sequence</param>
11+
<param name="sequence_name">singleevent_sequence</param>
1212
</generator>
1313
</id>
1414

dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/relationship/hibernate/Relationship.hbm.xml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
longer touches relationships via Hibernate. -->
1414

1515
<id name="id" column="relationshipid">
16-
<generator class="native"/>
16+
<generator class="sequence">
17+
<param name="sequence_name">relationship_sequence</param>
18+
</generator>
1719
</id>
1820

1921
&identifiableProperties;

dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/relationship/hibernate/RelationshipItem.hbm.xml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
items via Hibernate. -->
1313

1414
<id name="id" column="relationshipitemid">
15-
<generator class="native" />
15+
<generator class="sequence">
16+
<param name="sequence_name">relationshipitem_sequence</param>
17+
</generator>
1618
</id>
1719

1820
<many-to-one name="relationship" class="org.hisp.dhis.tracker.model.Relationship"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
-- DHIS2-21378: align tracker sequence names with the current table names and give
2+
-- relationship/relationshipitem their own sequences instead of the shared hibernate_sequence.
3+
4+
-- Tables were renamed long ago (trackedentityinstance -> trackedentity,
5+
-- programinstance -> enrollment) but the sequences kept the legacy names.
6+
alter sequence if exists trackedentityinstance_sequence rename to trackedentity_sequence;
7+
alter sequence if exists programinstance_sequence rename to enrollment_sequence;
8+
9+
-- After the event table split (V2_43_21) the SingleEvent Hibernate mapping kept drawing ids
10+
-- from the legacy programstageinstance_sequence while the JDBC import path used the canonical
11+
-- singleevent_sequence, so the two counters diverged. Resync the canonical sequence to the
12+
-- table's max id and drop the legacy sequence.
13+
select setval('singleevent_sequence', coalesce(max(eventid), 1)) from singleevent;
14+
drop sequence if exists programstageinstance_sequence;
15+
16+
-- relationship and relationshipitem drew ids from the shared, global hibernate_sequence
17+
-- (<generator class="native"/>). Give them dedicated sequences, seeded from the current max ids.
18+
create sequence if not exists relationship_sequence;
19+
select setval('relationship_sequence', coalesce(max(relationshipid), 1)) from relationship;
20+
21+
create sequence if not exists relationshipitem_sequence;
22+
select setval('relationshipitem_sequence', coalesce(max(relationshipitemid), 1)) from relationshipitem;

dhis-2/dhis-tracker/src/main/java/org/hisp/dhis/tracker/export/relationship/HibernateRelationshipStore.java

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545
import java.util.stream.Stream;
4646
import javax.annotation.Nonnull;
4747
import org.apache.commons.collections4.CollectionUtils;
48-
import org.hibernate.annotations.QueryHints;
4948
import org.hisp.dhis.common.IdentifiableObject;
5049
import org.hisp.dhis.common.SoftDeletableEntity;
5150
import org.hisp.dhis.common.SortDirection;
@@ -85,7 +84,12 @@ public HibernateRelationshipStore(
8584
JdbcTemplate jdbcTemplate,
8685
ApplicationEventPublisher publisher,
8786
AclService aclService) {
88-
super(entityManager, jdbcTemplate, publisher, Relationship.class, aclService, true);
87+
// cacheable=false: every query space this store reads (relationship, relationshipitem,
88+
// trackedentity, enrollment, trackerevent, singleevent) is written via raw JDBC in the
89+
// importer, which bypasses Hibernate's query-cache invalidation -- cached results would go
90+
// stale across imports (e.g. an empty duplicate-check result would silently disable
91+
// duplicate detection).
92+
super(entityManager, jdbcTemplate, publisher, Relationship.class, aclService, false);
8993
}
9094

9195
public Optional<TrackedEntity> findTrackedEntity(UID trackedEntity, boolean includeDeleted) {
@@ -176,14 +180,7 @@ public List<Relationship> getRelationshipsByRelationshipKeys(
176180
or (r.invertedKey in (:keys) and r.relationshipType.bidirectional = true))""";
177181
List<String> relationshipKeysAsString =
178182
relationshipKeys.stream().map(RelationshipKey::asString).toList();
179-
// Query cache must be off here: the tracker importer writes relationships through JDBC, which
180-
// bypasses Hibernate's query-cache invalidation. Leaving the cache on would let an earlier
181-
// empty result for a key linger across imports and silently disable duplicate detection.
182-
return getQuery(hql, Relationship.class)
183-
.setParameter("keys", relationshipKeysAsString)
184-
.setCacheable(false)
185-
.setHint(QueryHints.CACHEABLE, false)
186-
.list();
183+
return getQuery(hql, Relationship.class).setParameter("keys", relationshipKeysAsString).list();
187184
}
188185

189186
public List<RelationshipItem> getRelationshipItemsByTrackedEntity(

dhis-2/dhis-tracker/src/main/java/org/hisp/dhis/tracker/imports/bundle/persister/EnrollmentPersister.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public EnrollmentPersister(
7272

7373
@Override
7474
protected String sequenceName() {
75-
return "programinstance_sequence";
75+
return "enrollment_sequence";
7676
}
7777

7878
@Override

dhis-2/dhis-tracker/src/main/java/org/hisp/dhis/tracker/imports/bundle/persister/EntityWriteBatch.java

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,12 @@
7171
* <ul>
7272
* <li>TrackedEntity inserts are flushed via a multi-row JDBC INSERT against {@code trackedentity}
7373
* -- ids are pre-allocated by {@link AbstractTrackerPersister} from {@code
74-
* trackedentityinstance_sequence} in one round-trip.
74+
* trackedentity_sequence} in one round-trip.
7575
* <li>TrackedEntity updates are flushed via a single JDBC unnest UPDATE against {@code
7676
* trackedentity}, writing only the columns mutated by {@code TrackerObjectsMapper.map} on the
7777
* update branch.
7878
* <li>Enrollment inserts are flushed via a multi-row JDBC INSERT against {@code enrollment} --
79-
* ids are pre-allocated by {@link AbstractTrackerPersister} from {@code
80-
* programinstance_sequence}.
79+
* ids are pre-allocated by {@link AbstractTrackerPersister} from {@code enrollment_sequence}.
8180
* <li>Enrollment updates are flushed via a single JDBC unnest UPDATE against {@code enrollment},
8281
* writing the columns mutated by {@code TrackerObjectsMapper.map} on the update branch.
8382
* <li>TrackerEvent inserts are flushed via a multi-row JDBC INSERT against {@code trackerevent}
@@ -97,9 +96,9 @@
9796
* {@code relationship} with {@code from/to_relationshipitemid} left NULL, a multi-row INSERT
9897
* into {@code relationshipitem} for the (from + to) items, and an unnest UPDATE on {@code
9998
* relationship} to set the from/to FKs. The three-step shape breaks the circular FK between
100-
* the two tables, which is not deferrable in the live schema. Both tables use the shared
101-
* {@code hibernate_sequence}. Relationship is INSERT-only -- the persister rejects UPDATE
102-
* strategy upstream.
99+
* the two tables, which is not deferrable in the live schema. Ids come from {@code
100+
* relationship_sequence} and {@code relationshipitem_sequence}. Relationship is INSERT-only
101+
* -- the persister rejects UPDATE strategy upstream.
103102
* <li>TrackedEntityAttributeValues are flushed via JDBC against {@code
104103
* trackedentityattributevalue} -- a multi-row INSERT, a single unnest UPDATE keyed on the
105104
* composite ({@code trackedentityid}, {@code trackedentityattributeid}) PK, and a single
@@ -384,9 +383,8 @@ class EntityWriteBatch {
384383
private static final String SINGLE_EVENT_NOTES_INSERT_ROW = "(?, ?, ?)";
385384

386385
// Relationship is INSERT-only in tracker imports (RelationshipPersister.convert returns null on
387-
// UPDATE strategy). Both relationship and relationshipitem use `hibernate_sequence` (no
388-
// dedicated sequence was provisioned in any Flyway migration -- the hbm.xml `<generator
389-
// class="native"/>` resolves to the shared global counter).
386+
// UPDATE strategy). Relationship ids come from `relationship_sequence`, item ids from
387+
// `relationshipitem_sequence`.
390388
//
391389
// The two tables form a circular FK (relationship.from/to_relationshipitemid <->
392390
// relationshipitem.relationshipid) with non-deferrable constraints. We break the cycle by
@@ -1409,15 +1407,15 @@ private int bindRelationshipRow(PreparedStatement ps, int p, Relationship r) thr
14091407

14101408
/**
14111409
* Inserts the {@code relationshipitem} rows. Each Relationship has exactly two items (from + to);
1412-
* we allocate {@code 2 * relationships.size()} ids from {@code hibernate_sequence} in one
1410+
* we allocate {@code 2 * relationships.size()} ids from {@code relationshipitem_sequence} in one
14131411
* round-trip, assign them to the in-memory items (so the subsequent unnest UPDATE can read them
14141412
* back), then flatten the from/to items into a single multi-row INSERT.
14151413
*/
14161414
private void insertRelationshipItems(Connection conn) throws SQLException {
14171415
if (relationshipInserts.isEmpty()) {
14181416
return;
14191417
}
1420-
long[] itemIds = allocateIds(conn, "hibernate_sequence", 2 * relationshipInserts.size());
1418+
long[] itemIds = allocateIds(conn, "relationshipitem_sequence", 2 * relationshipInserts.size());
14211419
int cursor = 0;
14221420
for (Relationship r : relationshipInserts) {
14231421
r.getFrom().setId((int) itemIds[cursor++]);

dhis-2/dhis-tracker/src/main/java/org/hisp/dhis/tracker/imports/bundle/persister/RelationshipPersister.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,9 @@ public RelationshipPersister(
6363

6464
@Override
6565
protected String sequenceName() {
66-
// Shared with every other entity that uses Hibernate's `<generator class="native"/>`. No
67-
// dedicated relationship_sequence was provisioned in any Flyway migration. The 2
68-
// RelationshipItem
69-
// ids per Relationship are allocated separately inside
70-
// EntityWriteBatch.insertRelationshipItems.
71-
return "hibernate_sequence";
66+
// The 2 RelationshipItem ids per Relationship are allocated separately from
67+
// relationshipitem_sequence inside EntityWriteBatch.insertRelationshipItems.
68+
return "relationship_sequence";
7269
}
7370

7471
@Override

dhis-2/dhis-tracker/src/main/java/org/hisp/dhis/tracker/imports/bundle/persister/TrackedEntityPersister.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public TrackedEntityPersister(
6464

6565
@Override
6666
protected String sequenceName() {
67-
return "trackedentityinstance_sequence";
67+
return "trackedentity_sequence";
6868
}
6969

7070
@Override

dhis-2/dhis-tracker/src/main/java/org/hisp/dhis/tracker/model/Enrollment.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,10 @@ public class Enrollment extends BaseTrackerObject
9292

9393
@Id
9494
@Column(name = "enrollmentid")
95-
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "programinstance_sequence")
95+
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "enrollment_sequence")
9696
@SequenceGenerator(
97-
name = "programinstance_sequence",
98-
sequenceName = "programinstance_sequence",
97+
name = "enrollment_sequence",
98+
sequenceName = "enrollment_sequence",
9999
allocationSize = 1)
100100
private long id;
101101

0 commit comments

Comments
 (0)