File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -20,6 +20,7 @@ dependencies = [
2020 " colorlog" ,
2121 " charset-normalizer>=3.4.1" ,
2222 " json5" ,
23+ " filelock>=3.15.0" ,
2324]
2425requires-python = " >=3.11,<3.14"
2526readme = " README.md"
Original file line number Diff line number Diff line change 1212
1313import json5
1414import shtab
15+ from filelock import AsyncFileLock
1516
1617from vectorcode import __version__
1718
@@ -610,3 +611,18 @@ def config_logging(
610611 handlers = handlers ,
611612 level = level ,
612613 )
614+
615+
616+ class LockManager :
617+ """
618+ A class that manages file locks that protects the database files in daemon processes (LSP, MCP).
619+ """
620+
621+ def __init__ (self ) -> None :
622+ self .__locks : dict [str , AsyncFileLock ] = {}
623+
624+ def get (self , path : str | os .PathLike ) -> AsyncFileLock :
625+ path = str (expand_path (str (path ), True ))
626+ if self .__locks .get (path ) is None :
627+ self .__locks [path ] = AsyncFileLock (path ) # pyright: ignore[reportArgumentType]
628+ return self .__locks [path ]
Original file line number Diff line number Diff line change 55import socket
66import subprocess
77import sys
8+ from asyncio .subprocess import Process
89from typing import Any , AsyncGenerator
910from urllib .parse import urlparse
1011
@@ -261,3 +262,30 @@ async def list_collection_files(collection: AsyncCollection) -> list[str]:
261262 or []
262263 )
263264 )
265+
266+
267+ class ClientManager :
268+ __singleton = None
269+
270+ # keys: project roots
271+ # values: clients
272+ __clients : dict [str , AsyncClientAPI ] = {}
273+ __server_processes = []
274+
275+ @classmethod
276+ def get_instance (cls ) -> "ClientManager" :
277+ if cls .__singleton is None :
278+ cls .__singleton = ClientManager ()
279+ return cls .__singleton
280+
281+ async def get (self , configs : Config ) -> AsyncClientAPI :
282+ project_root = str (expand_path (str (configs .project_root ), True ))
283+ if self .__clients .get (project_root ) is None :
284+ if not await try_server (configs .db_url ):
285+ self .__server_processes .append (await start_server (configs ))
286+
287+ self .__clients [project_root ] = await get_client (configs )
288+ return self .__clients [project_root ]
289+
290+ def get_processes (self ) -> list [Process ]:
291+ return self .__server_processes
Original file line number Diff line number Diff line change 1212 get_project_config ,
1313 parse_cli_args ,
1414)
15+ from vectorcode .common import ClientManager
1516
1617logger = logging .getLogger (name = __name__ )
1718
@@ -63,12 +64,6 @@ async def async_main():
6364
6465 return await chunks (final_configs )
6566
66- from vectorcode .common import start_server , try_server
67-
68- server_process = None
69- if not await try_server (final_configs .db_url ):
70- server_process = await start_server (final_configs )
71-
7267 if final_configs .pipe : # pragma: nocover
7368 # NOTE: NNCF (intel GPU acceleration for sentence transformer) keeps showing logs.
7469 # This disables logs below ERROR so that it doesn't hurt the `pipe` output.
@@ -105,10 +100,9 @@ async def async_main():
105100 return_val = 1
106101 logger .error (traceback .format_exc ())
107102 finally :
108- if server_process is not None :
109- logger .info ("Shutting down the bundled Chromadb instance." )
110- server_process .terminate ()
111- await server_process .wait ()
103+ for p in ClientManager .get_instance ().get_processes ():
104+ p .terminate ()
105+ await p .wait ()
112106 return return_val
113107
114108
Original file line number Diff line number Diff line change 1717 expand_path ,
1818)
1919from vectorcode .common import (
20- get_client ,
20+ ClientManager ,
2121 get_collection ,
2222 verify_ef ,
2323)
@@ -160,7 +160,7 @@ async def query(configs: Config) -> int:
160160 "Having both chunk and document in the output is not supported!" ,
161161 )
162162 return 1
163- client = await get_client (configs )
163+ client = await ClientManager . get_instance (). get (configs )
164164 try :
165165 collection = await get_collection (client , configs , False )
166166 if not verify_ef (collection , configs ):
You can’t perform that action at this time.
0 commit comments