@@ -127,9 +127,9 @@ type Head struct {
127127 headPath string // path while block is actively appended to
128128 localPath string // path once block has been cut
129129
130- flushCh chan struct {} // this channel is closed once the Head should be flushed, should be used externally
131-
132- flushForcedTimer * time.Timer // this timer will phlare after the maximum
130+ inFlightProfiles sync. WaitGroup // ongoing ingestion requests.
131+ flushCh chan struct {} // this channel is closed once the Head should be flushed, should be used externally
132+ flushForcedTimer * time.Timer // this timer will phlare after the maximum
133133
134134 metaLock sync.RWMutex
135135 meta * block.Meta
@@ -569,8 +569,8 @@ func (h *Head) InRange(start, end model.Time) bool {
569569
570570// Returns underlying queries, the queriers should be roughly ordered in TS increasing order
571571func (h * Head ) Queriers () Queriers {
572- h .profiles .lock .RLock ()
573- defer h .profiles .lock .RUnlock ()
572+ h .profiles .rowsLock .RLock ()
573+ defer h .profiles .rowsLock .RUnlock ()
574574
575575 queriers := make ([]Querier , 0 , len (h .profiles .rowGroups )+ 1 )
576576 for idx := range h .profiles .rowGroups {
@@ -865,7 +865,9 @@ func (h *Head) Close() error {
865865 return merr .Err ()
866866}
867867
868- // Flush closes the head and writes data to disk
868+ // Flush closes the head and writes data to disk. No ingestion requests should
869+ // be made concurrently with the call, or after it returns.
870+ // The call is thread-safe for reads.
869871func (h * Head ) Flush (ctx context.Context ) error {
870872 start := time .Now ()
871873 defer func () {
@@ -880,7 +882,11 @@ func (h *Head) Flush(ctx context.Context) error {
880882}
881883
882884func (h * Head ) flush (ctx context.Context ) error {
883- if h .profiles .empty () {
885+ // Ensure all the in-flight ingestion requests have finished.
886+ // It must be guaranteed that no new inserts will happen
887+ // after the call start.
888+ h .inFlightProfiles .Wait ()
889+ if len (h .profiles .slice ) == 0 {
884890 level .Info (h .logger ).Log ("msg" , "head empty - no block written" )
885891 return os .RemoveAll (h .headPath )
886892 }
@@ -941,6 +947,20 @@ func (h *Head) flush(ctx context.Context) error {
941947 return err
942948 }
943949 h .metrics .blockDurationSeconds .Observe (h .meta .MaxTime .Sub (h .meta .MinTime ).Seconds ())
950+ return nil
951+ }
952+
953+ // Move moves the head directory to local blocks. The call is not thread-safe:
954+ // no concurrent reads and writes are allowed.
955+ //
956+ // After the call, head in-memory representation is not valid and should not
957+ // be accessed for querying.
958+ func (h * Head ) Move () error {
959+ // Remove intermediate row groups before the move as they are still
960+ // referencing files on the disk.
961+ if err := h .profiles .DeleteRowGroups (); err != nil {
962+ return err
963+ }
944964
945965 // move block to the local directory
946966 if err := os .MkdirAll (filepath .Dir (h .localPath ), defaultFolderMode ); err != nil {
0 commit comments