Initializes Sync Gateway indexes for datastore. Creates required indexes if not found, then waits for index readiness.
(ctx context.Context, n1QLStore base.N1QLStore, options InitializeIndexOptions)
| 393 | |
| 394 | // Initializes Sync Gateway indexes for datastore. Creates required indexes if not found, then waits for index readiness. |
| 395 | func InitializeIndexes(ctx context.Context, n1QLStore base.N1QLStore, options InitializeIndexOptions) error { |
| 396 | if options.NumPartitions < 1 { |
| 397 | return fmt.Errorf("Invalid number of partitions specified: %d, needs to be greater than 0", options.NumPartitions) |
| 398 | } |
| 399 | |
| 400 | requiredIndexes := make(sgIndexesToBuild, 0, len(sgIndexes)) |
| 401 | for _, sgIndex := range sgIndexes { |
| 402 | if !sgIndex.shouldCreate(options) { |
| 403 | base.DebugfCtx(ctx, base.KeyAll, "Skipping index: %s ...", sgIndex.simpleName) |
| 404 | continue |
| 405 | } |
| 406 | fullIndexName := sgIndex.fullIndexName(options.UseXattrs, options.NumPartitions) |
| 407 | requiredIndexes = append(requiredIndexes, sgIndexToBuild{fullIndexName: fullIndexName, sgIndex: sgIndex}) |
| 408 | } |
| 409 | |
| 410 | if len(requiredIndexes) == 0 { |
| 411 | // not expected to get here - all our collections require at least one index ... |
| 412 | base.AssertfCtx(ctx, "No indexes to create - expected at least one index to be created, but none were found") |
| 413 | return nil |
| 414 | } |
| 415 | |
| 416 | indexesMeta, err := base.GetIndexesMeta(ctx, n1QLStore, requiredIndexes.FullIndexNames()) |
| 417 | if err != nil { |
| 418 | base.WarnfCtx(ctx, "Error getting indexes meta: %v - continuing to create", err) |
| 419 | } |
| 420 | |
| 421 | // Happy-path optimization (for each collection): |
| 422 | // Drop indexes from the list if they're already online to avoid any per-index init cost. |
| 423 | requiredIndexes = slices.DeleteFunc(requiredIndexes, func(idx sgIndexToBuild) bool { |
| 424 | meta, exists := indexesMeta[idx.fullIndexName] |
| 425 | if exists && meta.State == base.IndexStateOnline { |
| 426 | base.DebugfCtx(ctx, base.KeyAll, "Index %s is already online", idx.fullIndexName) |
| 427 | // remove from list of indexes to create/wait for |
| 428 | return true |
| 429 | } |
| 430 | return false |
| 431 | }) |
| 432 | |
| 433 | if len(requiredIndexes) == 0 { |
| 434 | // all indexes are already online so we can return early without any per-index queries |
| 435 | base.InfofCtx(ctx, base.KeyAll, "Indexes ready - already online when checked") |
| 436 | return nil |
| 437 | } |
| 438 | |
| 439 | base.InfofCtx(ctx, base.KeyAll, "Initializing %d indexes with numReplicas: %d...", len(requiredIndexes), options.NumReplicas) |
| 440 | |
| 441 | for _, idx := range requiredIndexes { |
| 442 | err := idx.sgIndex.createIfNeeded(ctx, n1QLStore, options) |
| 443 | if err != nil { |
| 444 | if !errors.Is(err, base.ErrIndexBackgroundRetry) { |
| 445 | return base.RedactErrorf("Unable to install index %s: %v", base.MD(idx.sgIndex.simpleName), err) |
| 446 | } |
| 447 | } |
| 448 | } |
| 449 | |
| 450 | fullIndexNames := requiredIndexes.FullIndexNames() |
| 451 | // Issue BUILD INDEX for any deferred indexes. |
| 452 | buildErr := base.BuildDeferredIndexes(ctx, n1QLStore, fullIndexNames) |