Repository: influxdata/influxdb
File: tsdb/engine/tsm1/compact.go (Go)

Code before:
		if err := os.Remove(f); err != nil {
			return fmt.Errorf("error removing temp compaction file: %v", err)
		}
	}
	return nil
}

// writeNewFiles writes from the iterator into new TSM files, rotating
// to a new file once it has reached the max TSM file size.
func (c *Compactor) writeNewFiles(generation, sequence int, src []string, iter KeyIterator, throttle bool, logger *zap.Logger) ([]string, error) {
	// These are the new TSM files written
	var files []string

	for {
		sequence++

		// New TSM files are written to a temp file and renamed when fully completed.
		fileName := filepath.Join(c.Dir, c.formatFileName(generation, sequence)+"."+TSMFileExtension+"."+TmpTSMFileExtension)
		logger.Debug("Compacting files", zap.Int("file_count", len(src)), zap.String("output_file", fileName))

		// Write as much as possible to this file
		err := c.write(fileName, iter, throttle, logger)

		// We've hit the max file limit and there is more to write.  Create a new file
		// and continue.
		if errors.Is(err, errMaxFileExceeded) || errors.Is(err, ErrMaxBlocksExceeded) {
			files = append(files, fileName)
			logger.Debug("file size or block count exceeded, opening another output file", zap.String("output_file", fileName))
			continue
		} else if errors.Is(err, ErrNoValues) {
			logger.Debug("Dropping empty file", zap.String("output_file", fileName))
			// If the file only contained tombstoned entries, then it would be a 0 length
			// file that we can drop.
			if err := os.RemoveAll(fileName); err != nil {
				return nil, err
			}
			break
		} else if _, ok := err.(errCompactionInProgress); ok {
			// Don't clean up the file as another compaction is using it.  This should not happen as the
			// planner keeps track of which files are assigned to compaction plans now.
			return nil, err
		} else if err != nil {
			// We hit an error and didn't finish the compaction.  Abort.
			// Remove any tmp files we already completed
			// discard later errors to return the first one from the write() call
			for _, f := range files {
				_ = os.RemoveAll(f)
			}
			// Remove the temp file
			// discard later errors to return the first one from the write() call
			_ = os.RemoveAll(fileName)

Review comment (suggestion):
Not sure if it matters but since you are joining errors and then checking with `errors.Is` if there are multiple errors joined and `errMaxFileExceed` or `ErrMaxBlocksExceeded` is in the errors this will pass the test.

See the following example where I check for a single error. The function that returns two errors combined still passes the test. 
https://goplay.tools/snippet/b_YVLCYn5-j

I'm sure thats what you were expecting but just something I noticed with `errors.Is` 

Code after:

// removeTmpFiles is responsible for cleaning up a compaction that
// was started, but then abandoned before the temporary files were dealt with.
func (c *Compactor) removeTmpFiles(files []string) error {
	for _, f := range files {
		if err := os.Remove(f); err != nil {
			return fmt.Errorf("error removing temp compaction file: %v", err)
		}
	}
	return nil
}

// writeNewFiles writes from the iterator into new TSM files, rotating
// to a new file once it has reached the max TSM file size.
func (c *Compactor) writeNewFiles(generation, sequence int, src []string, iter KeyIterator, throttle bool, logger *zap.Logger) ([]string, error) {
	// These are the new TSM files written
	var files []string
	var eInProgress errCompactionInProgress

	for {
		sequence++

		// New TSM files are written to a temp file and renamed when fully completed.
		fileName := filepath.Join(c.Dir, c.formatFileName(generation, sequence)+"."+TSMFileExtension+"."+TmpTSMFileExtension)
		logger.Debug("Compacting files", zap.Int("file_count", len(src)), zap.String("output_file", fileName))

		// Write as much as possible to this file
		rollToNext, err := c.write(fileName, iter, throttle, logger)

		if rollToNext {
			// We've hit the max file limit and there is more to write.  Create a new file
			// and continue.
			files = append(files, fileName)
			logger.Debug("file size or block count exceeded, opening another output file", zap.String("output_file", fileName))
			continue
		} else if errors.Is(err, ErrNoValues) {
			logger.Debug("Dropping empty file", zap.String("output_file", fileName))
			// If the file only contained tombstoned entries, then it would be a 0 length
			// file that we can drop.
			if err := os.RemoveAll(fileName); err != nil {
				return nil, err
			}
			break
		} else if errors.As(err, &eInProgress) {
			if !errors.Is(eInProgress.err, fs.ErrExist) {
				logger.Error("error creating compaction file", zap.String("output_file", fileName), zap.Error(err))
			} else {
				// Don't clean up the file as another compaction is using it.  This should not happen as the
				// planner keeps track of which files are assigned to compaction plans now.
				logger.Warn("file exists, compaction in progress already", zap.String("output_file", fileName))
			}