github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/storage/stores/tsdb/store.go (about) 1 package tsdb 2 3 import ( 4 "fmt" 5 "sync" 6 7 "github.com/go-kit/log/level" 8 "github.com/prometheus/client_golang/prometheus" 9 "github.com/prometheus/prometheus/model/labels" 10 11 "github.com/grafana/loki/pkg/storage/chunk/client" 12 "github.com/grafana/loki/pkg/storage/chunk/fetcher" 13 "github.com/grafana/loki/pkg/storage/config" 14 "github.com/grafana/loki/pkg/storage/stores" 15 "github.com/grafana/loki/pkg/storage/stores/indexshipper" 16 "github.com/grafana/loki/pkg/storage/stores/indexshipper/downloads" 17 "github.com/grafana/loki/pkg/storage/stores/series" 18 "github.com/grafana/loki/pkg/storage/stores/tsdb/index" 19 util_log "github.com/grafana/loki/pkg/util/log" 20 ) 21 22 type store struct { 23 indexShipper indexshipper.IndexShipper 24 indexWriter IndexWriter 25 indexStore series.IndexStore 26 stopOnce sync.Once 27 } 28 29 type newStoreFactoryFunc func( 30 indexShipperCfg indexshipper.Config, 31 p config.PeriodConfig, 32 f *fetcher.Fetcher, 33 objectClient client.ObjectClient, 34 limits downloads.Limits, 35 tableRanges config.TableRanges, 36 reg prometheus.Registerer, 37 ) ( 38 chunkWriter stores.ChunkWriter, 39 indexStore series.IndexStore, 40 stopFunc func(), 41 err error, 42 ) 43 44 // NewStore creates a new store if not initialized already. 45 // Each call to NewStore will always build a new stores.ChunkWriter even if the store was already initialized since 46 // fetcher.Fetcher instances could be different due to periodic configs having different types of object storage configured 47 // for storing chunks. 48 // It also helps us make tsdb store a singleton because 49 // we do not need to build store for each schema config since we do not do any schema specific handling yet. 50 // If we do need to do schema specific handling, it would be a good idea to abstract away the handling since 51 // running multiple head managers would be complicated and wasteful. 52 var NewStore = func() newStoreFactoryFunc { 53 var storeInstance *store 54 return func( 55 indexShipperCfg indexshipper.Config, 56 p config.PeriodConfig, 57 f *fetcher.Fetcher, 58 objectClient client.ObjectClient, 59 limits downloads.Limits, 60 tableRanges config.TableRanges, 61 reg prometheus.Registerer, 62 ) ( 63 stores.ChunkWriter, 64 series.IndexStore, 65 func(), 66 error, 67 ) { 68 if storeInstance == nil { 69 storeInstance = &store{} 70 err := storeInstance.init(indexShipperCfg, objectClient, limits, tableRanges, reg) 71 if err != nil { 72 return nil, nil, nil, err 73 } 74 } 75 76 return NewChunkWriter(f, p, storeInstance.indexWriter), storeInstance.indexStore, storeInstance.Stop, nil 77 } 78 }() 79 80 func (s *store) init(indexShipperCfg indexshipper.Config, objectClient client.ObjectClient, 81 limits downloads.Limits, tableRanges config.TableRanges, reg prometheus.Registerer) error { 82 83 var err error 84 s.indexShipper, err = indexshipper.NewIndexShipper( 85 indexShipperCfg, 86 objectClient, 87 limits, 88 nil, 89 OpenShippableTSDB, 90 tableRanges, 91 prometheus.WrapRegistererWithPrefix("loki_tsdb_shipper_", reg), 92 ) 93 if err != nil { 94 return err 95 } 96 97 var indices []Index 98 99 if indexShipperCfg.Mode != indexshipper.ModeReadOnly { 100 var ( 101 nodeName = indexShipperCfg.IngesterName 102 dir = indexShipperCfg.ActiveIndexDirectory 103 ) 104 105 tsdbMetrics := NewMetrics(reg) 106 tsdbManager := NewTSDBManager( 107 nodeName, 108 dir, 109 s.indexShipper, 110 tableRanges, 111 util_log.Logger, 112 tsdbMetrics, 113 ) 114 115 headManager := NewHeadManager( 116 util_log.Logger, 117 dir, 118 tsdbMetrics, 119 tsdbManager, 120 ) 121 if err := headManager.Start(); err != nil { 122 return err 123 } 124 125 s.indexWriter = headManager 126 indices = append(indices, headManager) 127 } else { 128 s.indexWriter = failingIndexWriter{} 129 } 130 131 indices = append(indices, newIndexShipperQuerier(s.indexShipper, tableRanges)) 132 multiIndex, err := NewMultiIndex(indices...) 133 if err != nil { 134 return err 135 } 136 137 s.indexStore = NewIndexClient(multiIndex) 138 139 return nil 140 } 141 142 func (s *store) Stop() { 143 s.stopOnce.Do(func() { 144 if hm, ok := s.indexWriter.(*HeadManager); ok { 145 if err := hm.Stop(); err != nil { 146 level.Error(util_log.Logger).Log("msg", "failed to stop head manager", "err", err) 147 } 148 } 149 s.indexShipper.Stop() 150 }) 151 } 152 153 type failingIndexWriter struct{} 154 155 func (f failingIndexWriter) Append(_ string, _ labels.Labels, _ index.ChunkMetas) error { 156 return fmt.Errorf("index writer is not initialized due to tsdb store being initialized in read-only mode") 157 }