001/*- 002 * #%L 003 * HAPI FHIR Server - SQL Migration 004 * %% 005 * Copyright (C) 2014 - 2023 Smile CDR, Inc. 006 * %% 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 * #L% 019 */ 020package ca.uhn.fhir.jpa.migrate.taskdef; 021 022import org.apache.commons.lang3.builder.EqualsBuilder; 023import org.apache.commons.lang3.builder.HashCodeBuilder; 024import org.apache.commons.lang3.tuple.Pair; 025import org.slf4j.Logger; 026import org.slf4j.LoggerFactory; 027import org.springframework.jdbc.core.JdbcTemplate; 028 029import java.sql.SQLException; 030 031public class ForceIdMigrationCopyTask extends BaseTask { 032 private static final Logger ourLog = LoggerFactory.getLogger(ForceIdMigrationCopyTask.class); 033 034 public ForceIdMigrationCopyTask(String theProductVersion, String theSchemaVersion) { 035 super(theProductVersion, theSchemaVersion); 036 } 037 038 @Override 039 public void validate() { 040 // no-op 041 } 042 043 @Override 044 protected void doExecute() throws SQLException { 045 logInfo(ourLog, "Starting: migrate fhir_id from hfj_forced_id to hfj_resource.fhir_id"); 046 047 JdbcTemplate jdbcTemplate = newJdbcTemplate(); 048 049 Pair<Long, Long> range = jdbcTemplate.queryForObject( 050 "select min(RES_ID), max(RES_ID) from HFJ_RESOURCE", 051 (rs, rowNum) -> Pair.of(rs.getLong(1), rs.getLong(2))); 052 053 if (range == null || range.getLeft() == null) { 054 logInfo(ourLog, "HFJ_RESOURCE is empty. No work to do."); 055 return; 056 } 057 058 // run update in batches. 059 int rowsPerBlock = 50; // hfj_resource has roughly 50 rows per 8k block. 060 int batchSize = rowsPerBlock * 2000; // a few thousand IOPS gives a batch size around a second. 061 for (long batchStart = range.getLeft(); batchStart <= range.getRight(); batchStart = batchStart + batchSize) { 062 long batchEnd = batchStart + batchSize; 063 ourLog.info("Migrating client-assigned ids for pids: {}-{}", batchStart, batchEnd); 064 065 // This should be fast-ish since fhir_id isn't indexed yet, 066 // and we're walking both hfj_resource and hfj_forced_id in insertion order. 067 executeSql( 068 "hfj_resource", 069 "update hfj_resource " + "set fhir_id = coalesce( " 070 + // use first non-null value: forced_id if present, otherwise res_id 071 " (select f.forced_id from hfj_forced_id f where f.resource_pid = res_id), " 072 + " cast(res_id as varchar(64)) " 073 + " ) " 074 + "where fhir_id is null " 075 + "and res_id >= ? and res_id < ?", 076 batchStart, 077 batchEnd); 078 } 079 } 080 081 @Override 082 protected void generateHashCode(HashCodeBuilder theBuilder) { 083 // no-op - this is a singleton. 084 } 085 086 @Override 087 protected void generateEquals(EqualsBuilder theBuilder, BaseTask theOtherObject) { 088 // no-op - this is a singleton. 089 } 090}