| 3371 | } |
| 3372 | |
| 3373 | func (i *Ingester) closeAndDeleteUserTSDBIfIdle(userID string) tsdbCloseCheckResult { |
| 3374 | userDB, err := i.getTSDB(userID) |
| 3375 | if err != nil || userDB == nil || userDB.shipper == nil { |
| 3376 | // We will not delete local data when not using shipping to storage. |
| 3377 | return tsdbShippingDisabled |
| 3378 | } |
| 3379 | |
| 3380 | if result := userDB.shouldCloseTSDB(i.cfg.BlocksStorageConfig.TSDB.CloseIdleTSDBTimeout); !result.shouldClose() { |
| 3381 | return result |
| 3382 | } |
| 3383 | |
| 3384 | // This disables pushes and force-compactions. Not allowed to close while shipping is in progress. |
| 3385 | if !userDB.casState(active, closing) { |
| 3386 | return tsdbNotActive |
| 3387 | } |
| 3388 | |
| 3389 | // If TSDB is fully closed, we will set state to 'closed', which will prevent this deferred closing -> active transition. |
| 3390 | defer userDB.casState(closing, active) |
| 3391 | |
| 3392 | // Make sure we don't ignore any possible inflight requests. |
| 3393 | userDB.pushesInFlight.Wait() |
| 3394 | userDB.readInFlight.Wait() |
| 3395 | |
| 3396 | // Verify again, things may have changed during the checks and pushes. |
| 3397 | tenantDeleted := false |
| 3398 | if result := userDB.shouldCloseTSDB(i.cfg.BlocksStorageConfig.TSDB.CloseIdleTSDBTimeout); !result.shouldClose() { |
| 3399 | // This will also change TSDB state back to active (via defer above). |
| 3400 | return result |
| 3401 | } else if result == tsdbTenantMarkedForDeletion { |
| 3402 | tenantDeleted = true |
| 3403 | } |
| 3404 | |
| 3405 | // At this point there are no more pushes to TSDB, and no possible compaction. Normally TSDB is empty, |
| 3406 | // but if we're closing TSDB because of tenant deletion mark, then it may still contain some series. |
| 3407 | // We need to remove these series from series count. |
| 3408 | i.TSDBState.seriesCount.Sub(int64(userDB.Head().NumSeries())) |
| 3409 | |
| 3410 | dir := userDB.db.Dir() |
| 3411 | |
| 3412 | if err := userDB.Close(); err != nil { |
| 3413 | level.Error(i.logger).Log("msg", "failed to close idle TSDB", "user", userID, "err", err) |
| 3414 | return tsdbCloseFailed |
| 3415 | } |
| 3416 | |
| 3417 | level.Info(i.logger).Log("msg", "closed idle TSDB", "user", userID) |
| 3418 | |
| 3419 | // This will prevent going back to "active" state in deferred statement. |
| 3420 | userDB.casState(closing, closed) |
| 3421 | |
| 3422 | // Only remove user from TSDBState when everything is cleaned up |
| 3423 | // This will prevent concurrency problems when cortex are trying to open new TSDB - Ie: New request for a given tenant |
| 3424 | // came in - while closing the tsdb for the same tenant. |
| 3425 | // If this happens now, the request will get reject as the push will not be able to acquire the lock as the tsdb will be |
| 3426 | // in closed state |
| 3427 | defer func() { |
| 3428 | i.stoppedMtx.Lock() |
| 3429 | delete(i.TSDBState.dbs, userID) |
| 3430 | i.stoppedMtx.Unlock() |