@@ -24,11 +24,15 @@ type Index struct {
2424 getConn func (ctx context.Context ) (* sqlite3.Conn , error )
2525 llm llm.Client
2626 model string
27- lock sync.Mutex
27+ // rwLock allows concurrent Search operations while serializing Index/Delete
28+ rwLock sync.RWMutex
2829}
2930
3031// DeleteByID implements port.Index.
3132func (i * Index ) DeleteByID (ctx context.Context , ids ... model.SectionID ) error {
33+ i .rwLock .Lock ()
34+ defer i .rwLock .Unlock ()
35+
3236 err := i .withRetry (ctx , func (ctx context.Context , conn * sqlite3.Conn ) error {
3337 stmt , _ , err := conn .Prepare ("DELETE FROM embeddings WHERE section_id IN ( SELECT value FROM json_each(?) );" )
3438 if err != nil {
@@ -61,6 +65,9 @@ func (i *Index) DeleteByID(ctx context.Context, ids ...model.SectionID) error {
6165
6266// DeleteBySource implements port.Index.
6367func (i * Index ) DeleteBySource (ctx context.Context , source * url.URL ) error {
68+ i .rwLock .Lock ()
69+ defer i .rwLock .Unlock ()
70+
6471 err := i .withRetry (ctx , func (ctx context.Context , conn * sqlite3.Conn ) error {
6572 stmt , _ , err := conn .Prepare ("DELETE FROM embeddings WHERE source = ?;" )
6673 if err != nil {
@@ -86,25 +93,6 @@ func (i *Index) DeleteBySource(ctx context.Context, source *url.URL) error {
8693 return nil
8794}
8895
89- func (i * Index ) deleteBySource (ctx context.Context , conn * sqlite3.Conn , source * url.URL ) error {
90- stmt , _ , err := conn .Prepare ("DELETE FROM embeddings WHERE source = ?;" )
91- if err != nil {
92- return errors .WithStack (err )
93- }
94-
95- defer stmt .Close ()
96-
97- if err := stmt .BindText (1 , source .String ()); err != nil {
98- return errors .WithStack (err )
99- }
100-
101- if err := stmt .Exec (); err != nil {
102- return errors .WithStack (err )
103- }
104-
105- return nil
106- }
107-
10896type indexableChunk struct {
10997 Section model.Section
11098 Text string
@@ -127,6 +115,9 @@ const (
127115
128116// Index implements port.Index.
129117func (i * Index ) Index (ctx context.Context , document model.Document , funcs ... port.IndexOptionFunc ) error {
118+ i .rwLock .Lock ()
119+ defer i .rwLock .Unlock ()
120+
130121 opts := port .NewIndexOptions (funcs ... )
131122
132123 var chunksToProcess []* indexableChunk
@@ -348,6 +339,9 @@ func (i *Index) insertCollection(ctx context.Context, conn *sqlite3.Conn, embedd
348339
349340// Search implements port.Index.
350341func (i * Index ) Search (ctx context.Context , query string , opts port.IndexSearchOptions ) ([]* port.IndexSearchResult , error ) {
342+ i .rwLock .RLock ()
343+ defer i .rwLock .RUnlock ()
344+
351345 var searchResults []* port.IndexSearchResult
352346 err := i .withRetry (ctx , func (ctx context.Context , conn * sqlite3.Conn ) error {
353347 res , err := i .llm .Embeddings (ctx , []string {query })
@@ -478,9 +472,6 @@ func (i *Index) Search(ctx context.Context, query string, opts port.IndexSearchO
478472}
479473
480474func (i * Index ) withRetry (ctx context.Context , fn func (ctx context.Context , conn * sqlite3.Conn ) error , codes ... sqlite3.ErrorCode ) error {
481- i .lock .Lock ()
482- defer i .lock .Unlock ()
483-
484475 conn , err := i .getConn (ctx )
485476 if err != nil {
486477 return errors .WithStack (err )
0 commit comments