From 9296e80acfbe79f73c604f82c898d24efa69b2d0 Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Fri, 28 Nov 2025 20:22:43 +0100 Subject: [PATCH 01/10] ASSERT/ASSERT_TS: Add AssertOnAndClearRTError in fail case This should make finding the place of lingering RTEs easier. --- Packages/MIES/MIES_Utilities_ProgramFlow.ipf | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Packages/MIES/MIES_Utilities_ProgramFlow.ipf b/Packages/MIES/MIES_Utilities_ProgramFlow.ipf index 0ddc8d43b1..dbea241d8d 100644 --- a/Packages/MIES/MIES_Utilities_ProgramFlow.ipf +++ b/Packages/MIES/MIES_Utilities_ProgramFlow.ipf @@ -148,6 +148,10 @@ Function ASSERT(variable var, string errorMsg, [variable extendedOutput]) try AbortOnValue var == 0, 1 catch +#ifndef AUTOMATED_TESTING + AssertOnAndClearRTError() +#endif // !AUTOMATED_TESTING + if(ParamIsDefault(extendedOutput)) extendedOutput = 1 else @@ -284,6 +288,10 @@ threadsafe Function ASSERT_TS(variable var, string errorMsg, [variable extendedO try AbortOnValue var == 0, 1 catch +#ifndef AUTOMATED_TESTING + AssertOnAndClearRTError() +#endif // !AUTOMATED_TESTING + if(ParamIsDefault(extendedOutput)) extendedOutput = 1 else From d4b1c4fe17c7536e761f866bad5aab7c3dcb3d8c Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Fri, 28 Nov 2025 20:29:44 +0100 Subject: [PATCH 02/10] Catch lingering RTEs for labnotebook reading/writing This would have helped in debugging issue #2568. --- Packages/MIES/MIES_ExperimentDocumentation.ipf | 8 ++++++-- Packages/MIES/MIES_MiesUtilities_Logbook.ipf | 9 ++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Packages/MIES/MIES_ExperimentDocumentation.ipf b/Packages/MIES/MIES_ExperimentDocumentation.ipf index 7e6b243eae..495bf92484 100644 --- a/Packages/MIES/MIES_ExperimentDocumentation.ipf +++ b/Packages/MIES/MIES_ExperimentDocumentation.ipf @@ -192,8 +192,10 @@ static Function ED_createTextNotes(WAVE/T incomingTextualValues, WAVE/T incoming numCols = DimSize(incomingTextualValues, COLS) lastValidIncomingLayer = (DimSize(incomingTextualValues, LAYERS) == 0) ? 0 : (DimSize(incomingTextualValues, LAYERS) - 1) + + AssertOnAndClearRTError() for(i = 0; i < numCols; i += 1) - values[rowIndex][indizes[i]][0, lastValidIncomingLayer] = NormalizeToEOL(incomingTextualValues[0][i][r], "\n") + values[rowIndex][indizes[i]][0, lastValidIncomingLayer] = NormalizeToEOL(incomingTextualValues[0][i][r], "\n"); AbortOnRTE endfor SetNumberInWaveNote(values, NOTE_INDEX, rowIndex + 1) @@ -295,8 +297,10 @@ static Function ED_createWaveNotes(WAVE incomingNumericalValues, WAVE/T incoming numCols = DimSize(incomingNumericalValues, COLS) lastValidIncomingLayer = (DimSize(incomingNumericalValues, LAYERS) == 0) ? 0 : (DimSize(incomingNumericalValues, LAYERS) - 1) + + AssertOnAndClearRTError() for(i = 0; i < numCols; i += 1) - values[rowIndex][indizes[i]][0, lastValidIncomingLayer] = incomingNumericalValues[0][i][r] + values[rowIndex][indizes[i]][0, lastValidIncomingLayer] = incomingNumericalValues[0][i][r]; AbortOnRTE endfor SetNumberInWaveNote(values, NOTE_INDEX, rowIndex + 1) diff --git a/Packages/MIES/MIES_MiesUtilities_Logbook.ipf b/Packages/MIES/MIES_MiesUtilities_Logbook.ipf index 5b722be6d1..8a3b25e702 100644 --- a/Packages/MIES/MIES_MiesUtilities_Logbook.ipf +++ b/Packages/MIES/MIES_MiesUtilities_Logbook.ipf @@ -749,8 +749,10 @@ threadsafe Function/WAVE GetLastSettingNoCache(WAVE values, variable sweepNo, st endif endif - statusText[] = textualValues[i][settingCol][p] - lengths[] = strlen(statusTexT[p]) + AssertOnAndClearRTError() + statusText[] = textualValues[i][settingCol][p]; AbortOnRTE + + lengths[] = strlen(statusTexT[p]) // return if we have at least one non-empty entry if(Sum(lengths) > 0) @@ -848,7 +850,8 @@ threadsafe Function/WAVE GetLastSettingNoCache(WAVE values, variable sweepNo, st endif endif - status[] = numericalValues[i][settingCol][p] + AssertOnAndClearRTError() + status[] = numericalValues[i][settingCol][p]; AbortOnRTE if(HasOneValidEntry(status)) if(!ParamIsDefault(rowIndex)) From 571887077e79c0987c9c327c2a1a6ce847f6efff Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Fri, 28 Nov 2025 20:31:29 +0100 Subject: [PATCH 03/10] ASSERT/ASSERT_TS: Output time with milliseconds precision --- Packages/MIES/MIES_Utilities_ProgramFlow.ipf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Packages/MIES/MIES_Utilities_ProgramFlow.ipf b/Packages/MIES/MIES_Utilities_ProgramFlow.ipf index dbea241d8d..f5034f31c1 100644 --- a/Packages/MIES/MIES_Utilities_ProgramFlow.ipf +++ b/Packages/MIES/MIES_Utilities_ProgramFlow.ipf @@ -236,7 +236,7 @@ Function ASSERT(variable var, string errorMsg, [variable extendedOutput]) print stacktrace print "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - printf "Time: %s\r", GetIso8601TimeStamp(localTimeZone = 1) + printf "Time: %s\r", GetIso8601TimeStamp(localTimeZone = 1, numFracSecondsDigits = 3) printf "Locked device: [%s]\r", RemoveEnding(lockedDevicesStr, ";") printf "Current sweep: [%s]\r", TextWaveToList(sweeps, ";", trailSep = 0) printf "DAQ: [%s]\r", TextWaveToList(daqStates, ";", trailSep = 0) @@ -327,7 +327,7 @@ threadsafe Function ASSERT_TS(variable var, string errorMsg, [variable extendedO print stacktrace print "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - printf "Time: %s\r", GetIso8601TimeStamp(localTimeZone = 1) + printf "Time: %s\r", GetIso8601TimeStamp(localTimeZone = 1, numFracSecondsDigits = 3) printf "Experiment: %s (%s)\r", GetExperimentName(), GetExperimentFileType() printf "Igor Pro version: %s (%s)\r", GetIgorProVersion(), GetIgorProBuildVersion() print "################################" From 74f47fc317edbde1c0a423a6b0a87e4a54ff7745 Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Fri, 28 Nov 2025 20:35:22 +0100 Subject: [PATCH 04/10] ASSERT: Output fifo position --- Packages/MIES/MIES_Utilities_ProgramFlow.ipf | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Packages/MIES/MIES_Utilities_ProgramFlow.ipf b/Packages/MIES/MIES_Utilities_ProgramFlow.ipf index f5034f31c1..cde3bcce55 100644 --- a/Packages/MIES/MIES_Utilities_ProgramFlow.ipf +++ b/Packages/MIES/MIES_Utilities_ProgramFlow.ipf @@ -205,6 +205,7 @@ Function ASSERT(variable var, string errorMsg, [variable extendedOutput]) Make/FREE/T tpStates = {NONE} Make/FREE/T daqStates = {NONE} Make/FREE/T acqStates = {NONE} + Make/FREE/T fifoPos = {NONE} if(!SVAR_Exists(lockedDevices) || IsEmpty(lockedDevices)) lockedDevicesStr = NONE @@ -213,7 +214,7 @@ Function ASSERT(variable var, string errorMsg, [variable extendedOutput]) numLockedDevices = ItemsInList(lockedDevicesStr) - Redimension/N=(numLockedDevices) sweeps, daqStates, tpStates, acqStates + Redimension/N=(numLockedDevices) sweeps, daqStates, tpStates, acqStates, fifoPos for(i = 0; i < numLockedDevices; i += 1) device = StringFromList(i, lockedDevicesStr) @@ -224,6 +225,7 @@ Function ASSERT(variable var, string errorMsg, [variable extendedOutput]) tpStates[i] = TestPulseRunModeToString(testpulseMode) daqStates[i] = DAQRunModeToString(runMode) acqStates[i] = AS_StateToString(ROVar(GetAcquisitionState(device))) + fifoPos[i] = num2istr(ROVar(GetFifoPosition(device))) endfor endif @@ -242,6 +244,7 @@ Function ASSERT(variable var, string errorMsg, [variable extendedOutput]) printf "DAQ: [%s]\r", TextWaveToList(daqStates, ";", trailSep = 0) printf "Testpulse: [%s]\r", TextWaveToList(tpStates, ";", trailSep = 0) printf "Acquisition state: [%s]\r", TextWaveToList(acqStates, ";", trailSep = 0) + printf "Fifo position: [%s]\r", TextWaveToList(fifoPos, ";", trailSep = 0) printf "Experiment: %s (%s)\r", GetExperimentName(), GetExperimentFileType() printf "Igor Pro version: %s (%s)\r", GetIgorProVersion(), GetIgorProBuildVersion() print "MIES version:" From b1ecad97207867ebde4843455a9768c9688a648c Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Fri, 28 Nov 2025 20:35:33 +0100 Subject: [PATCH 05/10] GetLastSetting: Pass settingCol into GetLastSettingNoCache This then takes the fast path as we don't need to determine it again. --- Packages/MIES/MIES_MiesUtilities_Logbook.ipf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Packages/MIES/MIES_MiesUtilities_Logbook.ipf b/Packages/MIES/MIES_MiesUtilities_Logbook.ipf index 8a3b25e702..81f66c2a60 100644 --- a/Packages/MIES/MIES_MiesUtilities_Logbook.ipf +++ b/Packages/MIES/MIES_MiesUtilities_Logbook.ipf @@ -625,8 +625,8 @@ threadsafe Function/WAVE GetLastSetting(WAVE values, variable sweepNo, string se first = rowCache[sweepNo][%first][entrySourceTypeIndex] last = rowCache[sweepNo][%last][entrySourceTypeIndex] - WAVE/Z settings = GetLastSettingNoCache(values, sweepNo, setting, entrySourceType, \ - first = first, last = last, rowIndex = rowIndex) + WAVE/Z settings = GetLastSettingNoCache(values, sweepNo, setting, entrySourceType, \ + first = first, last = last, rowIndex = rowIndex, settingCol = settingCol) if(WaveExists(settings)) ASSERT_TS(first >= 0 && last >= 0 && rowIndex >= 0, "invalid return combination from GetLastSettingNoCache") From 3004b22ed0d54a6dd418c5bd406f7f839e7fbbb6 Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Fri, 28 Nov 2025 20:39:17 +0100 Subject: [PATCH 06/10] AFM_CallAnalysisFunctions: Distinguish between RTEs and Aborts in catch case And also tone down the message do the user. --- Packages/MIES/MIES_AnalysisFunctionManagement.ipf | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Packages/MIES/MIES_AnalysisFunctionManagement.ipf b/Packages/MIES/MIES_AnalysisFunctionManagement.ipf index 79097bc31e..fd0f057d69 100644 --- a/Packages/MIES/MIES_AnalysisFunctionManagement.ipf +++ b/Packages/MIES/MIES_AnalysisFunctionManagement.ipf @@ -14,7 +14,7 @@ /// @return Valid analysis function return types, zero otherwise, see also @ref AnalysisFunctionReturnTypes Function AFM_CallAnalysisFunctions(string device, variable eventType) - variable i, valid_f1, valid_f2, valid_f3, ret, DAC, sweepsInSet, hwIsSutter + variable i, valid_f1, valid_f2, valid_f3, ret, DAC, sweepsInSet, hwIsSutter, err variable realDataLengthAD, realDataLengthDA, sweepNo, fifoPositionAD, fifoPositionDA, sampleIntDA, sampleIntAD string func, msg STRUCT AnalysisFunction_V3 s @@ -170,8 +170,12 @@ Function AFM_CallAnalysisFunctions(string device, variable eventType) endif catch msg = GetRTErrMessage() - ClearRTError() - printf "The analysis function %s aborted with error \"%s\", this is dangerous and must *not* happen!\r", func, msg + err = ClearRTError() + if(err) + printf "The analysis function %s aborted due to a runtime error (%d) \"%s\".\r", func, err, msg + else + printf "The analysis function %s aborted with V_AbortCode (%d).\r", func, V_AbortCode + endif NVAR errorCounter = $GetAnalysisFuncErrorCounter(device) errorCounter += 1 From 2607d775312b727d2380e76a979ee2058cf0ec75 Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Tue, 2 Dec 2025 23:39:50 +0100 Subject: [PATCH 07/10] MIES_IVSCC.ipf: Disable cache across new experiments [1] [1]: https://github.com/AllenInstitute/MIES/issues/2568#issuecomment-3604231978 --- Packages/MIES/MIES_IVSCC.ipf | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Packages/MIES/MIES_IVSCC.ipf b/Packages/MIES/MIES_IVSCC.ipf index bd9359b2d9..4015ed9a6f 100644 --- a/Packages/MIES/MIES_IVSCC.ipf +++ b/Packages/MIES/MIES_IVSCC.ipf @@ -399,8 +399,7 @@ End Function IVS_NewExperimentWithCacheAndAutoloader() - Execute/P/Q "BackupCacheWaves()" + // disabling cache for now Execute/P/Q "NEWEXPERIMENT " - // restoring is done in IgorStartOrNewHook Execute/P/Q "CONF_AutoLoader()" End From 2faa47360294dca02df85333cbc3b8d49442bced Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Wed, 3 Dec 2025 22:19:05 +0100 Subject: [PATCH 08/10] GetLBRowCache/GetLBIndexCache: Make them work across experiments Since 8be5388114 (NewExperiment: Keep the cache waves across NewExperiment calls, 2025-10-02) we allow to keep the cache across experiments. For the labnotebook row and index cache keeping the cache across experiments is equivalent to deleting the logbook waves and then restarting over. But the upgrade path for both cases did not work as expected as we only did a full upgrade if the labnotebook was empty i.e. the GetLastSweepWithSetting call did not succeed. But if we added an entry for the first sweep, that would pass but then we would not overwrite entries from later sweeps from the previous labnotebook. --- Packages/MIES/MIES_WaveDataFolderGetters.ipf | 106 ++++++++++-------- .../UTF_PatchSeqDAScale_Sub.ipf | 35 ++++++ 2 files changed, 97 insertions(+), 44 deletions(-) diff --git a/Packages/MIES/MIES_WaveDataFolderGetters.ipf b/Packages/MIES/MIES_WaveDataFolderGetters.ipf index 91c0ef16cf..7ca7279bb8 100644 --- a/Packages/MIES/MIES_WaveDataFolderGetters.ipf +++ b/Packages/MIES/MIES_WaveDataFolderGetters.ipf @@ -2191,7 +2191,7 @@ End /// - One for each entrySourceType, mapped via EntrySourceTypeMapper() threadsafe Function/WAVE GetLBRowCache(WAVE values) - variable actual, sweepNo, first, last + variable actual, sweepNo, first, last, expected string key variable versionOfNewWave = 6 @@ -2202,32 +2202,41 @@ threadsafe Function/WAVE GetLBRowCache(WAVE values) WAVE/Z/D wv = CA_TryFetchingEntryFromCache(key, options = CA_OPTS_NO_DUPLICATE) if(ExistsWithCorrectLayoutVersion(wv, versionOfNewWave)) - if(actual == GetNumberFromWaveNote(wv, LABNOTEBOOK_MOD_COUNT)) + expected = GetNumberFromWaveNote(wv, LABNOTEBOOK_MOD_COUNT) + + // wave modification count tracking is only reliable while running + // inside a single experiment, not across experiments + if(actual == expected) return wv elseif(!MU_RunningInMainThread() && GetLockState(values) == 1) return wv else - // new entries were added so we need to propagate all entries to LABNOTEBOOK_GET_RANGE - // for sweep numbers >= than the currently acquired sweep - // this is required as the `last` element of the range can be changed if you add labnotebook - // entries and then query them and then add again. - - if(IsNumericWave(values)) - WAVE/Z sweeps = GetLastSweepWithSetting(values, "SweepNum", sweepNo) - elseif(IsTextWave(values)) - WAVE/Z sweeps = GetLastSweepWithSettingText(values, "SweepNum", sweepNo) - endif - - if(IsFinite(sweepNo)) - EnsureLargeEnoughWave(wv, indexShouldExist = sweepNo, dimension = ROWS, initialValue = LABNOTEBOOK_GET_RANGE) - first = limit(sweepNo - 1, 0, Inf) - last = sweepNo - Multithread wv[first, last][][] = LABNOTEBOOK_GET_RANGE - - // now we are up to date - SetNumberInWaveNote(wv, LABNOTEBOOK_MOD_COUNT, actual) - - return wv + if(actual > expected) + // new entries were added so we need to propagate all entries to LABNOTEBOOK_GET_RANGE + // for sweep numbers >= than the currently acquired sweep + // this is required as the `last` element of the range can be changed if you add labnotebook + // entries and then query them and then add again. + + if(IsNumericWave(values)) + WAVE/Z sweeps = GetLastSweepWithSetting(values, "SweepNum", sweepNo) + elseif(IsTextWave(values)) + WAVE/Z sweeps = GetLastSweepWithSettingText(values, "SweepNum", sweepNo) + endif + + if(IsFinite(sweepNo)) + EnsureLargeEnoughWave(wv, indexShouldExist = sweepNo, dimension = ROWS, initialValue = LABNOTEBOOK_GET_RANGE) + first = limit(sweepNo - 1, 0, Inf) + last = sweepNo + Multithread wv[first, last][][] = LABNOTEBOOK_GET_RANGE + + // now we are up to date + SetNumberInWaveNote(wv, LABNOTEBOOK_MOD_COUNT, actual) + + return wv + endif + else + // cache across experiments, so the stored wave modification is + // larger than the last labnotebook we cached, go for a full reset endif endif else @@ -2266,7 +2275,7 @@ End /// could not be found, and #LABNOTEBOOK_UNCACHED_VALUE if the cache is empty. threadsafe Function/WAVE GetLBIndexCache(WAVE values) - variable actual, sweepNo, first, last + variable actual, sweepNo, first, last, expected string key variable versionOfNewWave = 5 @@ -2277,30 +2286,39 @@ threadsafe Function/WAVE GetLBIndexCache(WAVE values) WAVE/Z/D wv = CA_TryFetchingEntryFromCache(key, options = CA_OPTS_NO_DUPLICATE) if(ExistsWithCorrectLayoutVersion(wv, versionOfNewWave)) - if(actual == GetNumberFromWaveNote(wv, LABNOTEBOOK_MOD_COUNT)) + expected = GetNumberFromWaveNote(wv, LABNOTEBOOK_MOD_COUNT) + + // wave modification count tracking is only reliable while running + // inside a single experiment, not across experiments + if(actual == expected) return wv elseif(!MU_RunningInMainThread() && GetLockState(values) == 1) return wv else - // new entries were added so we need to propagate all entries to uncached values - // for sweep numbers >= than the currently acquired sweep - - if(IsNumericWave(values)) - WAVE/Z sweeps = GetLastSweepWithSetting(values, "SweepNum", sweepNo) - elseif(IsTextWave(values)) - WAVE/Z sweeps = GetLastSweepWithSettingText(values, "SweepNum", sweepNo) - endif - - if(IsFinite(sweepNo)) - EnsureLargeEnoughWave(wv, indexShouldExist = sweepNo, dimension = ROWS, initialValue = LABNOTEBOOK_UNCACHED_VALUE) - first = limit(sweepNo - 1, 0, Inf) - last = sweepNo - Multithread wv[first, last][][] = LABNOTEBOOK_UNCACHED_VALUE - - // now we are up to date - SetNumberInWaveNote(wv, LABNOTEBOOK_MOD_COUNT, actual) - - return wv + if(actual > expected) + // new entries were added so we need to propagate all entries to uncached values + // for sweep numbers >= than the currently acquired sweep + + if(IsNumericWave(values)) + WAVE/Z sweeps = GetLastSweepWithSetting(values, "SweepNum", sweepNo) + elseif(IsTextWave(values)) + WAVE/Z sweeps = GetLastSweepWithSettingText(values, "SweepNum", sweepNo) + endif + + if(IsFinite(sweepNo)) + EnsureLargeEnoughWave(wv, indexShouldExist = sweepNo, dimension = ROWS, initialValue = LABNOTEBOOK_UNCACHED_VALUE) + first = limit(sweepNo - 1, 0, Inf) + last = sweepNo + Multithread wv[first, last][][] = LABNOTEBOOK_UNCACHED_VALUE + + // now we are up to date + SetNumberInWaveNote(wv, LABNOTEBOOK_MOD_COUNT, actual) + + return wv + endif + else + // cache across experiments, so the stored wave modification is + // larger than the last labnotebook we cached, go for a full reset endif endif else diff --git a/Packages/tests/HardwareAnalysisFunctions/UTF_PatchSeqDAScale_Sub.ipf b/Packages/tests/HardwareAnalysisFunctions/UTF_PatchSeqDAScale_Sub.ipf index ce18ee4da3..e1b9b388d3 100644 --- a/Packages/tests/HardwareAnalysisFunctions/UTF_PatchSeqDAScale_Sub.ipf +++ b/Packages/tests/HardwareAnalysisFunctions/UTF_PatchSeqDAScale_Sub.ipf @@ -2349,3 +2349,38 @@ static Function PS_DS_Sub11_REENTRY([string str]) CommonAnalysisFunctionChecks(str, sweepNo, setPassed) CheckPSQChunkTimes(str, {20, 520, 2020, 2520}) End + +static Function PS_DS_Sub12_preAcq(string device) + + Make/FREE asyncChannels = {2, 3} + AFH_AddAnalysisParameter("PSQ_DaScale_Sub_DA_0", "AsyncQCChannels", wv = asyncChannels) + + SetAsyncChannelProperties(device, asyncChannels, -1e6, +1e6) +End + +// UTF_TD_GENERATOR DataGenerators#DeviceNameGeneratorMD1 +static Function PS_DS_Sub12([string str]) + + PS_DS_Sub2(str = str) +End + +static Function PS_DS_Sub12_REENTRY([string str]) + + PS_DS_Sub2_REENTRY(str = str) + + BackupCacheWaves() +End + +// UTF_TD_GENERATOR DataGenerators#DeviceNameGeneratorMD1 +static Function PS_DS_Sub13([string str]) + + CA_FLushCache() + RestoreCacheWaves() + + PS_DS_Sub2(str = str) +End + +static Function PS_DS_Sub13_REENTRY([string str]) + + PS_DS_Sub2_REENTRY(str = str) +End From f3db64029eca117f275dd5af51880d26bfe864ce Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Wed, 3 Dec 2025 22:34:06 +0100 Subject: [PATCH 09/10] IVS_NewExperimentWithCacheAndAutoloader: Enable cache across experiments again This reverts commit 3ecf2cdbac (MIES_IVSCC.ipf: Disable cache across new experiments [1], 2025-12-02). Fixed in the previous commit. --- Packages/MIES/MIES_IVSCC.ipf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Packages/MIES/MIES_IVSCC.ipf b/Packages/MIES/MIES_IVSCC.ipf index 4015ed9a6f..bd9359b2d9 100644 --- a/Packages/MIES/MIES_IVSCC.ipf +++ b/Packages/MIES/MIES_IVSCC.ipf @@ -399,7 +399,8 @@ End Function IVS_NewExperimentWithCacheAndAutoloader() - // disabling cache for now + Execute/P/Q "BackupCacheWaves()" Execute/P/Q "NEWEXPERIMENT " + // restoring is done in IgorStartOrNewHook Execute/P/Q "CONF_AutoLoader()" End From 3f24022776e72f7f72f8aa212b61d2981be6db1a Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Wed, 10 Dec 2025 14:45:34 +0100 Subject: [PATCH 10/10] BackupCacheWaves: Throw away logbook cache waves The upgrade mechanism in GetLBRowCache/GetLBIndexCache relies on the wave modification count. And for pathological cases our logic there could still treat across experiment cache waves as belonging to a newly created labnotebook. This is for example if the labnotebook is modified as often as was stored in the wave modification count in the cache waves without reading it. So let's remove these cache waves before backing up the cache waves. --- Packages/MIES/MIES_MiesUtilities_Logbook.ipf | 37 ++++++++++++++++++++ Packages/MIES/MIES_MiesUtilities_System.ipf | 2 ++ Packages/tests/Basic/UTF_Utils_System.ipf | 2 +- 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/Packages/MIES/MIES_MiesUtilities_Logbook.ipf b/Packages/MIES/MIES_MiesUtilities_Logbook.ipf index 81f66c2a60..64889f5596 100644 --- a/Packages/MIES/MIES_MiesUtilities_Logbook.ipf +++ b/Packages/MIES/MIES_MiesUtilities_Logbook.ipf @@ -1987,3 +1987,40 @@ Function/S StringifyLogbookMode(variable mode) break endswitch End + +/// @brief Invalidates the row and index caches for all labnotebook and results wave +Function InvalidateLBIndexAndRowCaches() + + string device + + DFREF dfr = GetCacheFolder() + + if(IsDataFolderEmpty(dfr)) + return NaN + endif + + WAVE/T devices = ListToTextWave(GetAllDevices(), ";") + + // labnotebook (numerical and textual) of all devices + for(device : devices) + Make/FREE/WAVE valuesWave = {GetLBNumericalValues(device), GetLBTextualValues(device)} + + InvalidateLBIndexAndRowCaches_Impl(valuesWave) + endfor + + Make/FREE/WAVE valuesWave = {GetNumericalResultsValues(), GetTextualResultsValues()} + InvalidateLBIndexAndRowCaches_Impl(valuesWave) +End + +static Function InvalidateLBIndexAndRowCaches_Impl(WAVE valuesWave) + + string key + + for(WAVE values : valuesWave) + Make/FREE/T keys = {CA_CreateLBIndexCacheKey(values), CA_CreateLBRowCacheKey(values)} + + for(key : keys) + CA_DeleteCacheEntry(key) + endfor + endfor +End diff --git a/Packages/MIES/MIES_MiesUtilities_System.ipf b/Packages/MIES/MIES_MiesUtilities_System.ipf index 949566d4fc..9e9ab82bcf 100644 --- a/Packages/MIES/MIES_MiesUtilities_System.ipf +++ b/Packages/MIES/MIES_MiesUtilities_System.ipf @@ -213,6 +213,8 @@ Function BackupCacheWaves() variable i, numEntries string names = "" + InvalidateLBIndexAndRowCaches() + DFREF dfr = GetCacheFolder() WAVE/WAVE cacheWaves = ListToWaveRefWave(GetListOfObjects(dfr, ".*", fullPath = 1)) diff --git a/Packages/tests/Basic/UTF_Utils_System.ipf b/Packages/tests/Basic/UTF_Utils_System.ipf index 227eac7788..1fab30da58 100644 --- a/Packages/tests/Basic/UTF_Utils_System.ipf +++ b/Packages/tests/Basic/UTF_Utils_System.ipf @@ -131,7 +131,7 @@ static Function TestCacheBackupAndRestore() DFREF dfr = GetCacheFolder() name = GetListOfObjects(dfr, ".*") - CHECK_EQUAL_STR(name, "data;") + CHECK_EQUAL_STR(name, "data;keys;") WAVE/Z/SDFR=dfr new = $StringFromList(0, name) CHECK(!WaveRefsEqual(new, old))