github.com/grafana/pyroscope@v1.18.0/pkg/phlaredb/bucket/tenant_deletion_mark.go (about)

     1  // SPDX-License-Identifier: AGPL-3.0-only
     2  // Provenance-includes-location: https://github.com/cortexproject/cortex/blob/master/pkg/storage/tsdb/tenant_deletion_mark.go
     3  // Provenance-includes-license: Apache-2.0
     4  // Provenance-includes-copyright: The Cortex Authors.
     5  
     6  package bucket
     7  
     8  import (
     9  	"bytes"
    10  	"context"
    11  	"encoding/json"
    12  	"path"
    13  	"time"
    14  
    15  	"github.com/go-kit/log/level"
    16  	"github.com/pkg/errors"
    17  
    18  	"github.com/grafana/pyroscope/pkg/objstore"
    19  	util_log "github.com/grafana/pyroscope/pkg/util"
    20  )
    21  
    22  // Relative to user-specific prefix.
    23  const TenantDeletionMarkPath = "markers/tenant-deletion-mark.json"
    24  
    25  type TenantDeletionMark struct {
    26  	// Unix timestamp when deletion marker was created.
    27  	DeletionTime int64 `json:"deletion_time"`
    28  
    29  	// Unix timestamp when cleanup was finished.
    30  	FinishedTime int64 `json:"finished_time,omitempty"`
    31  }
    32  
    33  func NewTenantDeletionMark(deletionTime time.Time) *TenantDeletionMark {
    34  	return &TenantDeletionMark{DeletionTime: deletionTime.Unix()}
    35  }
    36  
    37  // Checks for deletion mark for tenant. Errors other than "object not found" are returned.
    38  func TenantDeletionMarkExists(ctx context.Context, bkt objstore.BucketReader, userID string) (bool, error) {
    39  	markerFile := path.Join(userID, "phlaredb/", TenantDeletionMarkPath)
    40  
    41  	return bkt.Exists(ctx, markerFile)
    42  }
    43  
    44  // Uploads deletion mark to the tenant location in the bucket.
    45  func WriteTenantDeletionMark(ctx context.Context, bkt objstore.Bucket, userID string, cfgProvider objstore.TenantConfigProvider, mark *TenantDeletionMark) error {
    46  	bkt = objstore.NewTenantBucketClient(userID, bkt, cfgProvider)
    47  
    48  	data, err := json.Marshal(mark)
    49  	if err != nil {
    50  		return errors.Wrap(err, "serialize tenant deletion mark")
    51  	}
    52  
    53  	return errors.Wrap(bkt.Upload(ctx, TenantDeletionMarkPath, bytes.NewReader(data)), "upload tenant deletion mark")
    54  }
    55  
    56  // Returns tenant deletion mark for given user, if it exists. If it doesn't exist, returns nil mark, and no error.
    57  func ReadTenantDeletionMark(ctx context.Context, bkt objstore.BucketReader, userID string) (*TenantDeletionMark, error) {
    58  	markerFile := path.Join(userID, "phlaredb/", TenantDeletionMarkPath)
    59  
    60  	r, err := bkt.Get(ctx, markerFile)
    61  	if err != nil {
    62  		if bkt.IsObjNotFoundErr(err) {
    63  			return nil, nil
    64  		}
    65  
    66  		return nil, errors.Wrapf(err, "failed to read deletion mark object: %s", markerFile)
    67  	}
    68  
    69  	mark := &TenantDeletionMark{}
    70  	err = json.NewDecoder(r).Decode(mark)
    71  
    72  	// Close reader before dealing with decode error.
    73  	if closeErr := r.Close(); closeErr != nil {
    74  		level.Warn(util_log.Logger).Log("msg", "failed to close bucket reader", "err", closeErr)
    75  	}
    76  
    77  	if err != nil {
    78  		return nil, errors.Wrapf(err, "failed to decode deletion mark object: %s", markerFile)
    79  	}
    80  
    81  	return mark, nil
    82  }