| 2774 | } |
| 2775 | |
| 2776 | func (i *Ingester) getOrCreateTSDB(userID string, force bool) (*userTSDB, error) { |
| 2777 | db, err := i.getTSDB(userID) |
| 2778 | if db != nil { |
| 2779 | if err != nil { |
| 2780 | level.Warn(i.logger).Log("msg", "error getting user DB but userDB is not null", "err", err, "userID", userID) |
| 2781 | } |
| 2782 | return db, nil |
| 2783 | } |
| 2784 | |
| 2785 | i.stoppedMtx.Lock() |
| 2786 | defer i.stoppedMtx.Unlock() |
| 2787 | |
| 2788 | // Check again for DB in the event it was created in-between locks |
| 2789 | var ok bool |
| 2790 | db, ok = i.TSDBState.dbs[userID] |
| 2791 | if ok { |
| 2792 | return db, nil |
| 2793 | } |
| 2794 | |
| 2795 | // We're ready to create the TSDB, however we must be sure that the ingester |
| 2796 | // is in the ACTIVE state, otherwise it may conflict with the transfer in/out. |
| 2797 | // The TSDB is created when the first series is pushed and this shouldn't happen |
| 2798 | // to a non-ACTIVE ingester, however we want to protect from any bug, cause we |
| 2799 | // may have data loss or TSDB WAL corruption if the TSDB is created before/during |
| 2800 | // a transfer in occurs. |
| 2801 | if ingesterState := i.lifecycler.GetState(); !force && ingesterState != ring.ACTIVE { |
| 2802 | return nil, fmt.Errorf(errTSDBCreateIncompatibleState, ingesterState) |
| 2803 | } |
| 2804 | |
| 2805 | gl := i.getInstanceLimits() |
| 2806 | if gl != nil && gl.MaxInMemoryTenants > 0 { |
| 2807 | if users := int64(len(i.TSDBState.dbs)); users >= gl.MaxInMemoryTenants { |
| 2808 | return nil, errMaxUsersLimitReached |
| 2809 | } |
| 2810 | } |
| 2811 | |
| 2812 | // Create the database and a shipper for a user |
| 2813 | db, err = i.createTSDB(userID) |
| 2814 | if err != nil { |
| 2815 | return nil, err |
| 2816 | } |
| 2817 | |
| 2818 | // Add the db to list of user databases |
| 2819 | i.TSDBState.dbs[userID] = db |
| 2820 | i.metrics.memUsers.Inc() |
| 2821 | |
| 2822 | return db, nil |
| 2823 | } |
| 2824 | |
| 2825 | func (i *Ingester) blockChunkQuerierFunc(userId string) tsdb.BlockChunkQuerierFunc { |
| 2826 | return func(b tsdb.BlockReader, mint, maxt int64) (storage.ChunkQuerier, error) { |