mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-10-03 16:45:33 -03:00
perf(rename): make bulk filename-template apply O(n) instead of O(n^2)
Applying a filename template to a large library re-did O(library) work for every renamed file: a full natsort resort plus whole-table SQLite rewrite and download-history resync after each rename, and a full scan plus resort of the entire recipe collection per renamed LoRA. On a 20k-model library with 300k recipes on a HDD this pushed "Apply to Library" into multi-day runs. - ModelScanner.defer_cache_persist(): bulk loops update the in-memory entry and indexes only; resort + persist + download-history sync run once at context exit, forced even on cancellation/error since files are already renamed on disk. Single-rename callers keep immediate per-call behavior. - RecipeScanner.build_lora_hash_index(): one-shot hash -> recipes index so per-file lookups are O(1); update_lora_filename_by_hash gains hash_index / defer_maintenance params, with a single finalize_bulk_filename_updates() resort at the end of a bulk session. - ModelLifecycleService.bulk_rename_session() / BulkRenameContext wire the deferred path through rename_model (hash index built lazily on first recipe-touching rename). - Blocking os.rename sequence offloaded via asyncio.to_thread so one file's HDD I/O no longer stalls the event loop (no cross-file parallelism). - Skip logic, per-batch WebSocket progress, cancellation, and result counters unchanged.
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
import asyncio
|
||||
import logging
|
||||
from contextlib import asynccontextmanager
|
||||
from dataclasses import dataclass
|
||||
from types import SimpleNamespace
|
||||
from typing import Any, Dict, List, Optional
|
||||
from typing import Any, AsyncIterator, Dict, List, Optional
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -547,7 +548,13 @@ class StubLifecycleService:
|
||||
self.cancel_on_rename = False
|
||||
self._scanner = scanner
|
||||
|
||||
async def rename_model(self, *, file_path: str, new_file_name: str) -> Dict[str, Any]:
|
||||
@asynccontextmanager
|
||||
async def bulk_rename_session(self) -> AsyncIterator[None]:
|
||||
yield None
|
||||
|
||||
async def rename_model(
|
||||
self, *, file_path: str, new_file_name: str, bulk_context: Any = None
|
||||
) -> Dict[str, Any]:
|
||||
if self.error is not None:
|
||||
raise self.error
|
||||
self.renames.append({"file_path": file_path, "new_file_name": new_file_name})
|
||||
|
||||
Reference in New Issue
Block a user