gemini-code-assist[bot] commented on code in PR #19673:
URL: https://github.com/apache/tvm/pull/19673#discussion_r3370384215


##########
web/src/opfs_store.ts:
##########
@@ -166,43 +283,178 @@ export class OPFSStore {
     return this.directoryPromise;
   }
 
-  private async readMetadata(
+  private async readRecord(
     fileHandle: OPFSFileHandle,
-  ): Promise<OPFSStoreMetadata | undefined> {
+  ): Promise<OPFSStoreRecord | undefined> {
     try {
       const text = await (await fileHandle.getFile()).text();
       const parsed = JSON.parse(text);
       if (
         parsed === undefined ||
         parsed === null ||
         typeof parsed !== "object" ||
-        typeof parsed.url !== "string"
+        typeof parsed.url !== "string" ||
+        !Number.isSafeInteger(parsed.nbytes) ||
+        parsed.nbytes < 0
       ) {
-        throw new Error("OPFSStore: invalid metadata format.");
+        return undefined;
       }
-      const metadata: OPFSStoreMetadata = {
+      const record: OPFSStoreRecord = {
         url: parsed.url,
+        nbytes: parsed.nbytes,
       };
       if (typeof parsed.contentType === "string") {
-        metadata.contentType = parsed.contentType;
+        record.contentType = parsed.contentType;
       }
-      return metadata;
+      return record;
     } catch (err) {
-      if (this.isNotFoundError(err)) {
-        // Treat metadata disappearance between lookup and read as a cache miss
+      if (
+        OPFSStore.getErrorName(err) === "SyntaxError" ||
+        this.handleCacheMissStateError(err)
+      ) {
         return undefined;
       }
       throw err;
     }
   }
 
-  private async writeFile(
+  private getResponseInit(
+    record: OPFSStoreRecord,
+  ): ResponseInit | undefined {
+    return record.contentType !== undefined
+      ? { headers: { "content-type": record.contentType } }
+      : undefined;
+  }
+
+  private async writeRecord(
     handle: OPFSFileHandle,
-    data: Blob | BufferSource | string,
+    record: OPFSStoreRecord,
   ): Promise<void> {
     const writable = await handle.createWritable();
-    await writable.write(data);
+    await writable.write(new TextEncoder().encode(JSON.stringify(record)));
+    await writable.close();
+  }
+
+  private async readPayload(handle: OPFSFileHandle): Promise<ArrayBuffer> {
+    const syncHandle = await this.openSyncAccessHandle(handle, "read-only");
+    return syncHandle !== undefined
+      ? this.readPayloadWithSyncHandle(syncHandle)
+      : (await handle.getFile()).arrayBuffer();
+  }
+
+  private async hasExpectedPayloadSize(
+    entry: OPFSStoredEntry,
+  ): Promise<boolean> {
+    const blob = await entry.payloadHandle.getFile();
+    return blob.size === entry.record.nbytes;
+  }
+
+  private async writePayload(
+    handle: OPFSFileHandle,
+    response: Response,
+  ): Promise<number> {
+    const syncHandle = await this.openSyncAccessHandle(handle, "readwrite");
+    if (syncHandle !== undefined) {
+      return this.writePayloadWithSyncHandle(syncHandle, response);
+    }
+    return this.writePayloadWithWritable(handle, response);
+  }
+
+  private async writePayloadWithWritable(
+    handle: OPFSFileHandle,
+    response: Response,
+  ): Promise<number> {
+    const writable = await handle.createWritable();
+    if (response.body !== null) {
+      let nbytes = 0;
+      const reader = response.body.getReader();
+      try {
+        while (true) {
+          const { done, value } = await reader.read();
+          if (done) {
+            break;
+          }
+          await writable.write(value);
+          nbytes += value.byteLength;
+        }
+      } finally {
+        reader.releaseLock();
+      }
+      await writable.close();
+      return nbytes;
+    }
+    const payload = await response.arrayBuffer();
+    await writable.write(payload);
     await writable.close();
+    return payload.byteLength;
+  }

Review Comment:
   ![high](https://www.gstatic.com/codereviewagent/high-priority.svg)
   
   If an error occurs during streaming or writing (for example, if the network 
connection is interrupted or the reader throws an error), the `writable` stream 
is never closed or aborted. In the Origin Private File System (OPFS), an 
unclosed `FileSystemWritableFileStream` retains an exclusive lock on the file. 
This can cause subsequent read or write operations on the same file to fail 
with a `NoModificationAllowedError` until the page is reloaded or garbage 
collection runs.
   
   We should wrap the write operations in a `try...catch` block and ensure that 
`writable.abort()` is called if an error occurs, which safely releases the lock 
and discards any partial temporary file.
   
   ```typescript
     private async writePayloadWithWritable(
       handle: OPFSFileHandle,
       response: Response,
     ): Promise<number> {
       const writable = await handle.createWritable();
       try {
         if (response.body !== null) {
           let nbytes = 0;
           const reader = response.body.getReader();
           try {
             while (true) {
               const { done, value } = await reader.read();
               if (done) {
                 break;
               }
               await writable.write(value);
               nbytes += value.byteLength;
             }
           } finally {
             reader.releaseLock();
           }
           await writable.close();
           return nbytes;
         }
         const payload = await response.arrayBuffer();
         await writable.write(payload);
         await writable.close();
         return payload.byteLength;
       } catch (err) {
         try {
           await writable.abort();
         } catch {
           // Ignore secondary errors during abort cleanup
         }
         throw err;
       }
     }
   ```



##########
web/src/opfs_store.ts:
##########
@@ -166,43 +283,178 @@ export class OPFSStore {
     return this.directoryPromise;
   }
 
-  private async readMetadata(
+  private async readRecord(
     fileHandle: OPFSFileHandle,
-  ): Promise<OPFSStoreMetadata | undefined> {
+  ): Promise<OPFSStoreRecord | undefined> {
     try {
       const text = await (await fileHandle.getFile()).text();
       const parsed = JSON.parse(text);
       if (
         parsed === undefined ||
         parsed === null ||
         typeof parsed !== "object" ||
-        typeof parsed.url !== "string"
+        typeof parsed.url !== "string" ||
+        !Number.isSafeInteger(parsed.nbytes) ||
+        parsed.nbytes < 0
       ) {
-        throw new Error("OPFSStore: invalid metadata format.");
+        return undefined;
       }
-      const metadata: OPFSStoreMetadata = {
+      const record: OPFSStoreRecord = {
         url: parsed.url,
+        nbytes: parsed.nbytes,
       };
       if (typeof parsed.contentType === "string") {
-        metadata.contentType = parsed.contentType;
+        record.contentType = parsed.contentType;
       }
-      return metadata;
+      return record;
     } catch (err) {
-      if (this.isNotFoundError(err)) {
-        // Treat metadata disappearance between lookup and read as a cache miss
+      if (
+        OPFSStore.getErrorName(err) === "SyntaxError" ||
+        this.handleCacheMissStateError(err)
+      ) {
         return undefined;
       }
       throw err;
     }
   }
 
-  private async writeFile(
+  private getResponseInit(
+    record: OPFSStoreRecord,
+  ): ResponseInit | undefined {
+    return record.contentType !== undefined
+      ? { headers: { "content-type": record.contentType } }
+      : undefined;
+  }
+
+  private async writeRecord(
     handle: OPFSFileHandle,
-    data: Blob | BufferSource | string,
+    record: OPFSStoreRecord,
   ): Promise<void> {
     const writable = await handle.createWritable();
-    await writable.write(data);
+    await writable.write(new TextEncoder().encode(JSON.stringify(record)));
+    await writable.close();
+  }
+
+  private async readPayload(handle: OPFSFileHandle): Promise<ArrayBuffer> {
+    const syncHandle = await this.openSyncAccessHandle(handle, "read-only");
+    return syncHandle !== undefined
+      ? this.readPayloadWithSyncHandle(syncHandle)
+      : (await handle.getFile()).arrayBuffer();
+  }
+
+  private async hasExpectedPayloadSize(
+    entry: OPFSStoredEntry,
+  ): Promise<boolean> {
+    const blob = await entry.payloadHandle.getFile();
+    return blob.size === entry.record.nbytes;
+  }

Review Comment:
   ![medium](https://www.gstatic.com/codereviewagent/medium-priority.svg)
   
   In `sync` mode, calling `entry.payloadHandle.getFile()` is an asynchronous 
operation that creates a `Blob` object. For large model weights (often hundreds 
of megabytes or gigabytes), creating a `Blob` just to check its size can 
introduce non-trivial overhead and disk/memory mapping latency.
   
   Since we are in `sync` mode, we can open a read-only sync access handle and 
call `getSize()` to retrieve the file size. This is a metadata-only operation 
that is extremely fast and avoids the overhead of creating a `Blob`.
   
   ```typescript
     private async hasExpectedPayloadSize(
       entry: OPFSStoredEntry,
     ): Promise<boolean> {
       if (this.accessMode === "sync") {
         const syncHandle = await 
this.openSyncAccessHandle(entry.payloadHandle, "read-only");
         if (syncHandle !== undefined) {
           try {
             return syncHandle.getSize() === entry.record.nbytes;
           } finally {
             syncHandle.close();
           }
         }
       }
       const blob = await entry.payloadHandle.getFile();
       return blob.size === entry.record.nbytes;
     }
   ```



##########
web/src/opfs_store.ts:
##########
@@ -166,43 +283,178 @@ export class OPFSStore {
     return this.directoryPromise;
   }
 
-  private async readMetadata(
+  private async readRecord(
     fileHandle: OPFSFileHandle,
-  ): Promise<OPFSStoreMetadata | undefined> {
+  ): Promise<OPFSStoreRecord | undefined> {
     try {
       const text = await (await fileHandle.getFile()).text();
       const parsed = JSON.parse(text);
       if (
         parsed === undefined ||
         parsed === null ||
         typeof parsed !== "object" ||
-        typeof parsed.url !== "string"
+        typeof parsed.url !== "string" ||
+        !Number.isSafeInteger(parsed.nbytes) ||
+        parsed.nbytes < 0
       ) {
-        throw new Error("OPFSStore: invalid metadata format.");
+        return undefined;
       }
-      const metadata: OPFSStoreMetadata = {
+      const record: OPFSStoreRecord = {
         url: parsed.url,
+        nbytes: parsed.nbytes,
       };
       if (typeof parsed.contentType === "string") {
-        metadata.contentType = parsed.contentType;
+        record.contentType = parsed.contentType;
       }
-      return metadata;
+      return record;
     } catch (err) {
-      if (this.isNotFoundError(err)) {
-        // Treat metadata disappearance between lookup and read as a cache miss
+      if (
+        OPFSStore.getErrorName(err) === "SyntaxError" ||
+        this.handleCacheMissStateError(err)
+      ) {
         return undefined;
       }
       throw err;
     }
   }
 
-  private async writeFile(
+  private getResponseInit(
+    record: OPFSStoreRecord,
+  ): ResponseInit | undefined {
+    return record.contentType !== undefined
+      ? { headers: { "content-type": record.contentType } }
+      : undefined;
+  }
+
+  private async writeRecord(
     handle: OPFSFileHandle,
-    data: Blob | BufferSource | string,
+    record: OPFSStoreRecord,
   ): Promise<void> {
     const writable = await handle.createWritable();
-    await writable.write(data);
+    await writable.write(new TextEncoder().encode(JSON.stringify(record)));
+    await writable.close();
+  }

Review Comment:
   ![medium](https://www.gstatic.com/codereviewagent/medium-priority.svg)
   
   Similar to `writePayloadWithWritable`, if `writable.write` throws an error, 
the `writable` stream is not closed or aborted, leaving the record file locked. 
We should wrap this in a `try...catch` block to abort the stream on failure.
   
   ```typescript
     private async writeRecord(
       handle: OPFSFileHandle,
       record: OPFSStoreRecord,
     ): Promise<void> {
       const writable = await handle.createWritable();
       try {
         await writable.write(new TextEncoder().encode(JSON.stringify(record)));
         await writable.close();
       } catch (err) {
         try {
           await writable.abort();
         } catch {
           // Ignore secondary errors during abort cleanup
         }
         throw err;
       }
     }
   ```



##########
web/src/opfs_store.ts:
##########
@@ -43,94 +51,193 @@ interface OPFSStorageManager {
   getDirectory?: () => Promise<OPFSDirectoryHandle>;
 }
 
-interface OPFSStoreMetadata {
+interface OPFSStoreRecord {
   url: string;
+  nbytes: number;
   contentType?: string;
 }
 
+interface OPFSStoredEntry {
+  payloadHandle: OPFSFileHandle;
+  record: OPFSStoreRecord;
+}
+
+interface OPFSSyncAccessHandle {
+  getSize(): number;
+  read(buffer: BufferSource, options?: { at?: number }): number;
+  write(buffer: BufferSource, options?: { at?: number }): number;
+  truncate(size: number): void;
+  flush(): void;
+  close(): void;
+}
+
+type OPFSGlobalScope = typeof globalThis & {
+  DedicatedWorkerGlobalScope?: new () => object;
+  FileSystemFileHandle?: {
+    prototype?: {
+      createSyncAccessHandle?: unknown;
+    };
+  };
+};
+
 const HASH_ALGORITHM = "SHA-256";
 const OPFS_STORE_ROOT_DIRECTORY = "tvmjs-opfs-store";
 
 export class OPFSStore {
   private readonly scope: string;
+  private readonly requestedAccessMode: OPFSAccessMode;
+  private accessMode: OPFSEffectiveAccessMode;
   private directoryPromise?: Promise<OPFSDirectoryHandle>;
 
-  constructor(scope: string) {
+  constructor(scope: string, accessMode: OPFSAccessMode = "async") {
     this.scope = scope;
+    this.requestedAccessMode = accessMode;
+    this.accessMode = OPFSStore.resolveAccessMode(accessMode);
   }
 
   static isAvailable(): boolean {
     const storage = OPFSStore.getStorageManager();
     return storage !== undefined && typeof storage.getDirectory === "function";
   }
 
+  private static resolveAccessMode(
+    accessMode: OPFSAccessMode,
+  ): OPFSEffectiveAccessMode {
+    if (accessMode !== "auto") {
+      return accessMode;
+    }
+    return OPFSStore.isDedicatedWorkerWithSyncAccessHandle()
+      ? "sync"
+      : "async";
+  }
+
   async has(url: string): Promise<boolean> {
-    return (await this.read(url)) !== undefined;
+    try {
+      const entry = await this.getStoredEntry(url);
+      if (entry === undefined) {
+        return false;
+      }
+      return this.hasExpectedPayloadSize(entry);
+    } catch (err) {
+      if (this.handleCacheMissStateError(err)) {
+        return false;
+      }
+      throw err;
+    }
   }
 
   async read(url: string): Promise<Response | undefined> {
-    const directory = await this.getScopedDirectory();
-    const baseName = await this.hashUrl(url);
-    const dataHandle = await this.getFileHandleIfExists(
-      directory,
-      `${baseName}.bin`,
-      false,
-    );
-    if (dataHandle === undefined) {
-      return undefined;
+    try {
+      const entry = await this.getStoredEntry(url);
+      if (entry === undefined) {
+        return undefined;
+      }
+      if (this.accessMode === "async") {
+        const blob = await entry.payloadHandle.getFile();
+        if (blob.size !== entry.record.nbytes) {
+          return undefined;
+        }
+        return new Response(blob, this.getResponseInit(entry.record));
+      }
+      const payload = await this.readPayload(entry.payloadHandle);
+      if (payload.byteLength !== entry.record.nbytes) {
+        return undefined;
+      }
+      return new Response(payload, this.getResponseInit(entry.record));
+    } catch (err) {
+      if (this.handleCacheMissStateError(err)) {
+        return undefined;
+      }
+      throw err;
     }
-    const dataBlob = await dataHandle.getFile();
-    const metadataHandle = await this.getFileHandleIfExists(
-      directory,
-      `${baseName}.meta.json`,
-      false,
-    );
-    let metadata: OPFSStoreMetadata | undefined = undefined;
-    if (metadataHandle !== undefined) {
-      metadata = await this.readMetadata(metadataHandle);
-      if (metadata?.url !== undefined && metadata.url !== url) {
-        throw new Error("OPFSStore: metadata URL does not match key URL.");
+  }

Review Comment:
   ![medium](https://www.gstatic.com/codereviewagent/medium-priority.svg)
   
   In `sync` mode, `read(url)` eagerly reads the entire payload into an 
`ArrayBuffer` in JS memory via `readPayload` before wrapping it in a 
`Response`. Eagerly loading large files (like model weights) into JS memory can 
cause high memory pressure or out-of-memory (OOM) errors in the worker.
   
   Since `read(url)` returns a `Response` object, we should always wrap a lazy 
`Blob` (obtained via `getFile()`) instead of an eager `ArrayBuffer`. This 
allows the browser to handle the file content lazily or stream it, which is 
much more memory-efficient. Callers who specifically need an `ArrayBuffer` 
should use `readArrayBuffer(url)` instead, which is already optimized to use 
the sync access handle directly.
   
   This also simplifies the `read` method by removing the need to branch on 
`this.accessMode`.
   
   ```typescript
     async read(url: string): Promise<Response | undefined> {
       try {
         const entry = await this.getStoredEntry(url);
         if (entry === undefined) {
           return undefined;
         }
         const blob = await entry.payloadHandle.getFile();
         if (blob.size !== entry.record.nbytes) {
           return undefined;
         }
         return new Response(blob, this.getResponseInit(entry.record));
       } catch (err) { 
         if (this.handleCacheMissStateError(err)) {
           return undefined;
         }
         throw err;
       }
     }
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to