From a0d763a3bb663a41123da37816566360dc68ce0e Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Tue, 6 Oct 2026 14:31:39 -0400 Subject: [PATCH] Commit each court's code deletes with its reload updateAll deleted every changed court's rows up front, and the first court's commit published all of those deletes. Until each later court reloaded, it showed its old installedversion with missing rows. A court whose policy request failed stayed empty until the next run. Delete each court's tables right before reloading it, so the delete, new rows, and new installedversion commit together. replaceAll/replaceSome empty every court's tables but kept their installed versions, so a court reloaded at the same Tyler version looked unchanged to anything keyed on versions. Drop installedversion first; each court gets its version back as it reloads, and courts that replaceSome doesn't reload are picked up by the next refresh. Co-Authored-By: Claude Opus 5.5 --- .../litlab/efsp/ecfcodes/CodeUpdater.java | 35 ++++++------------- .../efsp/tyler/ecfcodes/TylerCodeUpdater.java | 10 ++++-- 2 files changed, 17 insertions(+), 28 deletions(-) diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/ecfcodes/CodeUpdater.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/ecfcodes/CodeUpdater.java index da49ae79..86ad58bf 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/ecfcodes/CodeUpdater.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/ecfcodes/CodeUpdater.java @@ -19,7 +19,6 @@ import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiFunction; @@ -321,34 +320,10 @@ public boolean updateAll( return false; } - // Drop each of tables that need to be updated Savepoint sp = cd.setSavepoint("court update savepoint"); Map> rawVersionsToUpdate = cd.getVersionsToUpdate(); Map> versionsToUpdate = makeOrRemoveUnsupportedTables(rawVersionsToUpdate, cd); - Instant startDel = Instant.now(); - log.info( - "Removing {} court entries, over {} queries", - versionsToUpdate.size(), - versionsToUpdate.values().stream().map(List::size).reduce(0, (a, b) -> a + b)); - for (Entry> courtAndTables : versionsToUpdate.entrySet()) { - final String courtLocation = courtAndTables.getKey(); - List tables = courtAndTables.getValue(); - log.debug( - "In {},\nremoving entries for court {} for tables: {}", - cd.getJurisdiction(), - courtLocation, - tables); - for (String table : tables) { - Instant delTime = Instant.now(); - - // Will ignore tables that don't exist. - cd.deleteFromTable(table, courtLocation); - - updateDuration = updateDuration.plus(Duration.between(delTime, Instant.now())); - } - } - log.info("Took {} to remove existing tables", Duration.between(startDel, Instant.now())); Instant startPolicy = Instant.now(); Map> policies = streamPolicies( @@ -360,6 +335,12 @@ public boolean updateAll( for (var policy : policies.entrySet()) { final String courtLocation = policy.getKey(); final List tables = versionsToUpdate.get(courtLocation); + // Delete right before reloading, so the delete, the new rows, and the new installedversion + // commit together. Readers never see a court's old version with its rows missing. + for (String table : tables) { + // Will ignore tables that don't exist. + cd.deleteFromTable(table, courtLocation); + } if (!downloadCourtTables( courtLocation, Optional.of(tables), cd, urlGetter, policy.getValue())) { log.warn("Failed updating court {}'s tables {}", courtLocation, tables); @@ -384,6 +365,10 @@ public boolean replaceAll( CodeUrlGetter urlGetter, CodeDatabaseAPI cd) throws SQLException, IOException, JAXBException, URISyntaxException { + cd.setAutoCommit(false); + // All tables for all courts are about to be emptied; drop all versions too. + // Each court gets its version back when it reloads. + cd.deleteFromTable("installedversion"); return replaceSome(systemUrls, codeInfoGetter, urlGetter, cd, List.of()); } diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/tyler/ecfcodes/TylerCodeUpdater.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/tyler/ecfcodes/TylerCodeUpdater.java index 0efaabaa..f58e29e8 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/tyler/ecfcodes/TylerCodeUpdater.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/tyler/ecfcodes/TylerCodeUpdater.java @@ -134,8 +134,12 @@ public static boolean executeCommand( if (command.equalsIgnoreCase("replaceall")) { return cu.replaceAll(systemUrls, codelistGetter, codeUrlGetter, cd); } else if (command.equalsIgnoreCase("replacesome")) { - return cu.replaceSome( - systemUrls, codelistGetter, codeUrlGetter, cd, args.subList(1, args.size())); + var someLocations = args.subList(1, args.size()); + if (someLocations.isEmpty()) { + log.error("Need to provide args of locations to replace (gave none)"); + return false; + } + return cu.replaceSome(systemUrls, codelistGetter, codeUrlGetter, cd, someLocations); } else if (command.equalsIgnoreCase("refresh")) { return cu.updateAll(systemUrls, codelistGetter, codeUrlGetter, cd); } else { @@ -161,7 +165,7 @@ public static boolean executeCommand( */ public static void main(String[] args) throws Exception { if (args.length < 1) { - log.error("Need to pass in a subprogram: downloadIndiv, or refresh"); + log.error("Need to pass in a subprogram: downloadIndiv, refresh, replacesome, replaceall"); System.exit(1); }