@@ -37,11 +37,12 @@ import (
3737)
3838
3939type trainRequest struct {
40- finalSample bool
41- sampleSize int
42- ackCh chan error
43- sample segment.Segment
44- trainingParams * index.TrainingParams
40+ finalSample bool
41+ sampleSize int
42+ ackCh chan error
43+ sample segment.Segment
44+ trainingParams * index.TrainingParams
45+ removedFileWriterIDs map [string ]struct {}
4546}
4647
4748type vectorTrainer struct {
@@ -85,6 +86,7 @@ func moveFile(sourcePath, destPath string) error {
8586 return nil
8687}
8788
89+ // update with the new writer API
8890func (t * vectorTrainer ) persistToBolt (trainReq * trainRequest ) error {
8991 tx , err := t .parent .rootBolt .Begin (true )
9092 if err != nil {
@@ -159,6 +161,16 @@ func (t *vectorTrainer) trainLoop() {
159161 t .config [index .TrainingKey ] = trainReq .trainingParams
160162 }
161163
164+ // remove any file writer ids that are no longer in use
165+ if trainReq .removedFileWriterIDs != nil {
166+ err := t .removeFileWriterIDs (trainReq .removedFileWriterIDs )
167+ if err != nil {
168+ trainReq .ackCh <- fmt .Errorf ("error removing file writer ids: %v" , err )
169+ close (trainReq .ackCh )
170+ return
171+ }
172+ }
173+
162174 // no sample segment: just persist state if this is the final sample and move on.
163175 if sampleSeg == nil {
164176 if trainReq .finalSample {
@@ -430,31 +442,76 @@ func (t *vectorTrainer) updateBolt(snapshotsBucket *util.BoltBucketImpl, key []b
430442 return nil
431443}
432444
433- func (t * vectorTrainer ) removeFileWriterIDs (ids map [string ]struct {}) error {
445+ func (t * vectorTrainer ) dropFileWriterIDs (ids map [string ]struct {}) error {
434446 t .m .Lock ()
435447 defer t .m .Unlock ()
436- path := filepath .Join (t .parent .path , index .TrainedIndexFileName )
437- writer , err := util .NewFileWriter ([]byte (path ))
448+
449+ trainReq := & trainRequest {
450+ ackCh : make (chan error ),
451+ removedFileWriterIDs : ids ,
452+ }
453+ t .trainCh <- trainReq
454+ err := <- trainReq .ackCh
455+ if err != nil {
456+ return fmt .Errorf ("train_vector: dropFileWriterIDs() err'd out with: %w" , err )
457+ }
458+
459+ return err
460+ }
461+
462+ func (t * vectorTrainer ) removeFileWriterIDs (ids map [string ]struct {}) error {
463+ // create a new writer to update the trainerBucket in bolt
464+ boltPath := filepath .Join (t .parent .path , "root.bolt" )
465+ writer , err := util .NewFileWriter ([]byte (boltPath ))
438466 if err != nil {
439467 return err
440468 }
441469
470+ // only the writer id needs to be updated in the bucket
471+ err = t .parent .rootBolt .Update (func (tx * util.BoltTxImpl ) error {
472+ snapshots := tx .Bucket (util .BoltSnapshotsBucket )
473+ if snapshots == nil {
474+ return nil
475+ }
476+ c := snapshots .Cursor ()
477+ for k , _ := c .First (); k != nil ; k , _ = c .Next () {
478+ if bytes .Equal (k , util .BoltTrainerKey ) {
479+ trainerBucket := snapshots .GetBucket (k )
480+ if trainerBucket == nil {
481+ continue
482+ }
483+ oldWriterID , err := trainerBucket .Get (util .BoltMetaDataFileWriterIDKey , nil )
484+ if err != nil {
485+ return err
486+ }
487+ if _ , ok := ids [string (oldWriterID )]; ok {
488+ err = trainerBucket .Put (util .BoltMetaDataFileWriterIDKey , []byte (writer .Id ()), writer )
489+ if err != nil {
490+ return err
491+ }
492+ }
493+ }
494+ }
495+ return nil
496+ })
497+
498+ // invoke the merge API and let the zap side of things handle the update of writer IDs and also
499+ // the data in the trained index.
500+ trainedIndexPath := filepath .Join (t .parent .path , index .TrainedIndexFileName )
442501 if encryptedIndex , ok := t .trainedIndex .segment .(segment.SegmentWithCallbacks ); ok {
443502 if _ , ok := ids [encryptedIndex .CallbackId ()]; ok {
444-
445503 _ , _ , err := t .parent .segPlugin .MergeUsing ([]segment.Segment {t .trainedIndex .segment },
446- []* roaring.Bitmap {nil , nil }, path + ".tmp" , t .parent .closeCh , nil , t .config )
504+ []* roaring.Bitmap {nil , nil }, trainedIndexPath + ".tmp" , t .parent .closeCh , nil , t .config )
447505 if err != nil {
448506 return err
449507 }
450508
451- // todo: handle removeFileWriterIDs call happens during training
452509 t .trainedIndex .segment .Close ()
453- if err = moveFile (path + ".tmp" , path ); err != nil {
510+ if err = moveFile (trainedIndexPath + ".tmp" , trainedIndexPath ); err != nil {
454511 return err
455512 }
456513
457- trainedIndex , err := t .parent .segPlugin .OpenUsing (path , t .config )
514+ trainedIndex , err := t .parent .segPlugin .OpenUsing (trainedIndexPath , t .config )
458515 if err != nil {
459516 return err
460517 }
@@ -465,6 +522,9 @@ func (t *vectorTrainer) removeFileWriterIDs(ids map[string]struct{}) error {
465522
466523 }
467524 }
525+ return err
526+ }
527+
468528func (t * vectorTrainer ) FileWriterIDsInUse () (map [string ]struct {}, error ) {
469529 t .m .RLock ()
470530 defer t .m .RUnlock ()
0 commit comments