long updateTracker(final DSLContext context, final long updateTimeMs) {
        ensureTracker(context, updateTimeMs);

        // Lock the row so we can check then update
        final Long dbUpdateTimeMs = NullSafe.get(context.select(CONFIG_UPDATE_TRACKER.UPDATE_TIME_MS)
                        .from(CONFIG_UPDATE_TRACKER)
                        .where(CONFIG_UPDATE_TRACKER.ID.eq(TRACKER_ID))
                        .forUpdate()
                        .fetchOne(),
                Record1::value1);

        Objects.requireNonNull(dbUpdateTimeMs);

        if (dbUpdateTimeMs >= updateTimeMs) {
            LOGGER.debug("Config tracker {} is ahead of {}", dbUpdateTimeMs, updateTimeMs);
            // Another thread has updated it with a more recent time so just use that
            return dbUpdateTimeMs;
        } else {
            LOGGER.debug("Updated config tracker to {}", updateTimeMs);
            context.update(CONFIG_UPDATE_TRACKER)
                    .set(CONFIG_UPDATE_TRACKER.UPDATE_TIME_MS, updateTimeMs)
                    .where(CONFIG_UPDATE_TRACKER.ID.eq(TRACKER_ID))
                    .execute();
            return updateTimeMs;
        }
    }
The tracker table means we have a simple way of checking if any of the DB config has changed
which can include removal of records. ANY mutation of the config table MUST also
call updateTracker
stroom-config/stroom-config-global-impl-db/src/main/java/stroom/config/global/impl/db/ConfigPropertyDaoImpl.java