@@ -48,6 +48,7 @@ const (
48
48
)
49
49
50
50
const (
51
+ ClearLine = "\033 [2K"
51
52
HideCursor = "\033 [?25l"
52
53
ShowCursor = "\033 [?25h"
53
54
)
@@ -78,6 +79,8 @@ var flagDisableAdaptiveSearch = flag.Bool(
78
79
var flagMemStore = flag .Bool ("memstore" , false , "Use in-memory store instead of CockroachDB" )
79
80
var flagDBConnStr = flag .String ("db" , "postgresql://root@localhost:26257" ,
80
81
"Database connection string (when not using --memstore)" )
82
+ var flagCreateIndexAfterImport = flag .Bool ("index-after" , false ,
83
+ "Create vector index after data import instead of during table creation (SQL provider only)" )
81
84
82
85
// vecbench benchmarks vector index in-memory build and search performance on a
83
86
// variety of datasets. Datasets are downloaded from the
@@ -125,7 +128,7 @@ func main() {
125
128
// Hide the cursor, but ensure it's restored on exit, including Ctrl+C.
126
129
c := make (chan os.Signal , 1 )
127
130
signal .Notify (c , os .Interrupt , syscall .SIGTERM )
128
- stopper .RunAsyncTask (ctx , "Ctrl+C" , func (context.Context ) {
131
+ err := stopper .RunAsyncTask (ctx , "Ctrl+C" , func (context.Context ) {
129
132
select {
130
133
case <- c :
131
134
fmt .Print (ShowCursor )
@@ -136,12 +139,17 @@ func main() {
136
139
break
137
140
}
138
141
})
142
+ if err != nil {
143
+ fmt .Printf ("Failed to install Ctrl-C handler: %v\n " , err )
144
+ }
139
145
fmt .Print (HideCursor )
140
146
defer fmt .Print (ShowCursor )
141
147
142
- // Start pprof server at http://localhost:8080/debug/pprof/
148
+ // Start pprof server at http://localhost:8080/debug/pprof/.
143
149
go func () {
144
- http .ListenAndServe ("localhost:8080" , nil )
150
+ if err := http .ListenAndServe ("localhost:8080" , nil ); err != nil {
151
+ fmt .Printf ("Failed to start pprof server: %v\n " , err )
152
+ }
145
153
}()
146
154
147
155
switch flag .Arg (0 ) {
@@ -340,6 +348,14 @@ func (vb *vectorBench) BuildIndex() {
340
348
panic (err )
341
349
}
342
350
351
+ // Create index immediately if flag is not set (default behavior).
352
+ if ! * flagCreateIndexAfterImport {
353
+ err = vb .provider .CreateIndex (vb .ctx )
354
+ if err != nil {
355
+ panic (err )
356
+ }
357
+ }
358
+
343
359
// Compute percentile latencies.
344
360
estimator := NewPercentileEstimator (1000 )
345
361
@@ -368,7 +384,7 @@ func (vb *vectorBench) BuildIndex() {
368
384
var lastInserted int
369
385
batchSize := * flagBatchSize
370
386
371
- // Reset the dataset to start from the beginning
387
+ // Reset the dataset to start from the beginning.
372
388
vb .data .Reset ()
373
389
374
390
for {
@@ -384,7 +400,7 @@ func (vb *vectorBench) BuildIndex() {
384
400
trainBatch := vb .data .Train
385
401
insertedBefore := int (insertCount .Load ())
386
402
387
- // Create primary keys for this batch
403
+ // Create primary keys for this batch.
388
404
primaryKeys := make ([]cspann.KeyBytes , trainBatch .Count )
389
405
keyBuf := make (cspann.KeyBytes , trainBatch .Count * 4 )
390
406
for i := range trainBatch .Count {
@@ -456,6 +472,50 @@ func (vb *vectorBench) BuildIndex() {
456
472
}
457
473
}
458
474
475
+ // Create index after import if flag is set.
476
+ if * flagCreateIndexAfterImport {
477
+ if ! * flagHideProgress {
478
+ fmt .Println ()
479
+ }
480
+ startIndexTime := timeutil .Now ()
481
+
482
+ // Start index creation in a goroutine to track progress.
483
+ done := make (chan error , 1 )
484
+ go func () {
485
+ done <- vb .provider .CreateIndex (vb .ctx )
486
+ }()
487
+
488
+ // Track progress until CreateIndex returns.
489
+ ticker := time .NewTicker (time .Second )
490
+ defer ticker .Stop ()
491
+
492
+ for {
493
+ select {
494
+ case err := <- done :
495
+ // CreateIndex returned, stop tracking.
496
+ if err != nil {
497
+ panic (err )
498
+ }
499
+ fmt .Printf (ClearLine + White + "\r Vector index creation completed in %v\n " + Reset ,
500
+ roundDuration (timeutil .Since (startIndexTime )))
501
+ goto indexCreated
502
+ case <- ticker .C :
503
+ if * flagHideProgress {
504
+ break
505
+ }
506
+ // Check progress.
507
+ progress , err := vb .provider .CheckIndexCreationStatus (vb .ctx )
508
+ if err != nil {
509
+ fmt .Printf (Red + "Error checking index status: %v\n " + Reset , err )
510
+ } else {
511
+ fmt .Printf (ClearLine + White + "\r Index creation progress: %.1f%% in %v" + Reset ,
512
+ progress * 100 , timeutil .Since (startIndexTime ).Truncate (time .Second ))
513
+ }
514
+ }
515
+ }
516
+ indexCreated:
517
+ }
518
+
459
519
fmt .Printf (White + "\n Built index in %v\n " + Reset , roundDuration (startAt .Elapsed ()))
460
520
461
521
// Ensure that index is persisted so it can be reused.
@@ -494,6 +554,11 @@ func (vb *vectorBench) ensureDataset(ctx context.Context) {
494
554
func newVectorProvider (
495
555
stopper * stop.Stopper , datasetName string , dims int , distanceMetric vecpb.DistanceMetric ,
496
556
) (VectorProvider , error ) {
557
+ // Validate flag compatibility.
558
+ if * flagCreateIndexAfterImport && * flagMemStore {
559
+ return nil , errors .New ("--create-index-after-import flag cannot be used with --memstore" )
560
+ }
561
+
497
562
options := cspann.IndexOptions {
498
563
MinPartitionSize : minPartitionSize ,
499
564
MaxPartitionSize : maxPartitionSize ,
0 commit comments