From a33385682f6456d5ffc44fd1f4d061c2643ed82b Mon Sep 17 00:00:00 2001 From: Ingo Fischer Date: Wed, 16 Oct 2024 21:51:35 +0200 Subject: [PATCH] Fix cc (#1289) * Lock reactor on timers ... to prevent error sin CC cluster with parallel run ning state changes * add more potential lock-issue cases * Adjust tests ... we need to wait a bit longer now * ALso test window covering needs to be adjusted * Fixes and make Async Storage not that slow --- .../storage/StorageBackendAsyncJsonFile.ts | 35 +++++++++++++++++-- .../level-control/LevelControlServer.ts | 6 ++-- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/chip-testing/src/storage/StorageBackendAsyncJsonFile.ts b/chip-testing/src/storage/StorageBackendAsyncJsonFile.ts index f9b15ab81e..7c1408cbe9 100644 --- a/chip-testing/src/storage/StorageBackendAsyncJsonFile.ts +++ b/chip-testing/src/storage/StorageBackendAsyncJsonFile.ts @@ -9,6 +9,8 @@ import { MaybeAsyncStorage, StorageBackendMemory, SupportedStorageTypes, + Time, + createPromise, fromJson, toJson, } from "@matter/general"; @@ -18,6 +20,8 @@ export class StorageBackendAsyncJsonFile extends MaybeAsyncStorage { /** We store changes after a value was set to the storage, but not more often than this setting (in ms). */ private closed = false; private store?: StorageBackendMemory; + private currentStoreItPromise?: Promise; + private lastStoredTime = 0; constructor(private readonly path: string) { super(); @@ -36,6 +40,7 @@ export class StorageBackendAsyncJsonFile extends MaybeAsyncStorage { } this.store = new StorageBackendMemory(data); this.store.initialize(); + this.lastStoredTime = Time.nowMs(); } get initialized() { @@ -88,15 +93,40 @@ export class StorageBackendAsyncJsonFile extends MaybeAsyncStorage { throw new InternalError("Storage not initialized."); } if (this.closed) return; + if (this.currentStoreItPromise !== undefined) { + return; + } + await this.storeIt(); + } + + private async storeIt(forced = false) { + if (this.store === undefined) { + throw new InternalError("Storage not initialized."); + } + if (this.closed) return; + if (!forced && this.lastStoredTime < Time.nowMs() - 1000) { + return; + } + if (this.currentStoreItPromise !== undefined) { + await this.currentStoreItPromise; + } + + const { promise, rejecter, resolver } = createPromise(); const json = this.toJson(this.store.data); - await writeFile(this.path, json, "utf8"); + writeFile(this.path, json, "utf8") + .then(resolver, rejecter) + .finally(() => { + this.currentStoreItPromise = undefined; + }); + this.currentStoreItPromise = promise; + return promise; } override async close() { if (this.store === undefined) { return; } - await this.commit(); + await this.storeIt(true); this.closed = true; this.store.close(); } @@ -127,6 +157,7 @@ export class StorageBackendAsyncJsonFile extends MaybeAsyncStorage { throw new InternalError("Storage not initialized."); } this.store.clearAll(contexts); + await this.commit(); } private toJson(object: any) { diff --git a/packages/node/src/behaviors/level-control/LevelControlServer.ts b/packages/node/src/behaviors/level-control/LevelControlServer.ts index c970f2f612..dc4337a254 100644 --- a/packages/node/src/behaviors/level-control/LevelControlServer.ts +++ b/packages/node/src/behaviors/level-control/LevelControlServer.ts @@ -37,7 +37,7 @@ const LevelControlLogicBase = LevelControlBehavior.with(LevelControl.Feature.OnO * following methods to natively use device features to correctly support the transition times. For this the default * implementation uses special protected methods which are used by the real commands and are only responsible for the * actual value change logic. The benefit of this structure is that basic data validations and options checks are - * already done and you can focus on the actual hardware interaction: + * already done, and you can focus on the actual hardware interaction: * * {@link LevelControlServerLogic.moveToLevelLogic} Logic to move the value to a defined level with a transition time * * {@link LevelControlServerLogic.moveLogic} Logic to move the value up or down with a defined rate * * {@link LevelControlServerLogic.stepLogic} Logic to step the value up or down with a defined step size and transition @@ -342,8 +342,8 @@ export class LevelControlServerLogic extends LevelControlLogicBase { return this.stopLogic(effectiveOptions); } - override stopWithOnOff() { - return this.stopLogic(); + override stopWithOnOff(request: LevelControl.StopRequest) { + return this.stop(request); } /**