| 695 | } |
| 696 | |
| 697 | func (s *LiveStore) getOrCreateInstance(tenantID string) (*instance, error) { |
| 698 | s.instancesMtx.RLock() |
| 699 | inst, ok := s.instances[tenantID] |
| 700 | s.instancesMtx.RUnlock() |
| 701 | |
| 702 | if ok { |
| 703 | return inst, nil |
| 704 | } |
| 705 | |
| 706 | s.instancesMtx.Lock() |
| 707 | defer s.instancesMtx.Unlock() |
| 708 | |
| 709 | // Double-check in case another goroutine created it |
| 710 | if inst, ok := s.instances[tenantID]; ok { |
| 711 | return inst, nil |
| 712 | } |
| 713 | |
| 714 | // Create new instance |
| 715 | inst, err := newInstance(tenantID, s.cfg, s.wal, s.completeBlockEncoding, s.completeBlockLifecycle, s.overrides, s.logger) |
| 716 | if err != nil { |
| 717 | return nil, fmt.Errorf("failed to create instance for tenant %s: %w", tenantID, err) |
| 718 | } |
| 719 | |
| 720 | s.instances[tenantID] = inst |
| 721 | |
| 722 | s.startPerTenantCutToWalLoop(inst) |
| 723 | s.runInBackground(func() { |
| 724 | s.perTenantCleanupLoop(inst) |
| 725 | }) |
| 726 | |
| 727 | return inst, nil |
| 728 | } |
| 729 | |
| 730 | func (s *LiveStore) getInstances() []*instance { |
| 731 | s.instancesMtx.RLock() |