github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/ctl/service/r2/store/kv/store.go (about)

     1  // Copyright (c) 2017 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE
    20  
    21  package kv
    22  
    23  import (
    24  	"errors"
    25  	"fmt"
    26  
    27  	"github.com/m3db/m3/src/ctl/service/r2"
    28  	r2store "github.com/m3db/m3/src/ctl/service/r2/store"
    29  	merrors "github.com/m3db/m3/src/metrics/errors"
    30  	"github.com/m3db/m3/src/metrics/rules"
    31  	"github.com/m3db/m3/src/metrics/rules/view"
    32  	"github.com/m3db/m3/src/metrics/rules/view/changes"
    33  	"github.com/m3db/m3/src/x/clock"
    34  	xerrors "github.com/m3db/m3/src/x/errors"
    35  )
    36  
    37  type store struct {
    38  	nowFn        clock.NowFn
    39  	opts         StoreOptions
    40  	ruleStore    rules.Store
    41  	updateHelper rules.RuleSetUpdateHelper
    42  }
    43  
    44  var errNilValidator = errors.New("no validator set on StoreOptions so validation is not applicable")
    45  
    46  // NewStore returns a new service that knows how to talk to a kv backed r2 store.
    47  func NewStore(rs rules.Store, opts StoreOptions) r2store.Store {
    48  	clockOpts := opts.ClockOptions()
    49  	updateHelper := rules.NewRuleSetUpdateHelper(opts.RuleUpdatePropagationDelay())
    50  	return &store{
    51  		nowFn:        clockOpts.NowFn(),
    52  		opts:         opts,
    53  		ruleStore:    rs,
    54  		updateHelper: updateHelper,
    55  	}
    56  }
    57  
    58  func (s *store) FetchNamespaces() (view.Namespaces, error) {
    59  	nss, err := s.ruleStore.ReadNamespaces()
    60  	if err != nil {
    61  		return view.Namespaces{}, handleUpstreamError(err)
    62  	}
    63  
    64  	namespaces, err := nss.NamespacesView()
    65  	if err != nil {
    66  		return view.Namespaces{}, handleUpstreamError(err)
    67  	}
    68  
    69  	liveNss := make([]view.Namespace, 0, len(namespaces.Namespaces))
    70  	for _, ns := range namespaces.Namespaces {
    71  		if !ns.Tombstoned {
    72  			liveNss = append(liveNss, ns)
    73  		}
    74  	}
    75  
    76  	return view.Namespaces{
    77  		Version:    namespaces.Version,
    78  		Namespaces: liveNss,
    79  	}, nil
    80  }
    81  
    82  func (s *store) ValidateRuleSet(rs view.RuleSet) error {
    83  	validator := s.opts.Validator()
    84  	// If no validator is set, then the validation functionality is not applicable.
    85  	if validator == nil {
    86  		return errNilValidator
    87  	}
    88  
    89  	return handleUpstreamError(validator.ValidateSnapshot(rs))
    90  }
    91  
    92  func (s *store) UpdateRuleSet(
    93  	rsChanges changes.RuleSetChanges,
    94  	version int,
    95  	uOpts r2store.UpdateOptions,
    96  ) (view.RuleSet, error) {
    97  	rs, err := s.ruleStore.ReadRuleSet(rsChanges.Namespace)
    98  	if err != nil {
    99  		return view.RuleSet{}, handleUpstreamError(err)
   100  	}
   101  	// If ruleset version fetched from KV matches the change set version,
   102  	// the check and set operation will succeed if the underlying
   103  	// KV version remains the same before the change is committed and fail otherwise.
   104  	// If the fetched version doesn't match, we will fail fast.
   105  	if version != rs.Version() {
   106  		return view.RuleSet{}, r2.NewConflictError(fmt.Sprintf(
   107  			"ruleset version mismatch: current version=%d, expected version=%d",
   108  			rs.Version(),
   109  			version,
   110  		))
   111  	}
   112  
   113  	mutable := rs.ToMutableRuleSet().Clone()
   114  	err = mutable.ApplyRuleSetChanges(rsChanges, s.newUpdateMeta(uOpts))
   115  	if err != nil {
   116  		return view.RuleSet{}, handleUpstreamError(err)
   117  	}
   118  	err = s.ruleStore.WriteRuleSet(mutable)
   119  	if err != nil {
   120  		return view.RuleSet{}, handleUpstreamError(err)
   121  	}
   122  
   123  	return s.FetchRuleSetSnapshot(rsChanges.Namespace)
   124  }
   125  
   126  func (s *store) CreateNamespace(
   127  	namespaceID string,
   128  	uOpts r2store.UpdateOptions,
   129  ) (view.Namespace, error) {
   130  	nss, err := s.ruleStore.ReadNamespaces()
   131  	if err != nil {
   132  		return view.Namespace{}, handleUpstreamError(err)
   133  	}
   134  
   135  	meta := s.newUpdateMeta(uOpts)
   136  	revived, err := nss.AddNamespace(namespaceID, meta)
   137  	if err != nil {
   138  		return view.Namespace{}, handleUpstreamError(err)
   139  	}
   140  
   141  	rs := rules.NewEmptyRuleSet(namespaceID, meta)
   142  	if revived {
   143  		rawRs, err := s.ruleStore.ReadRuleSet(namespaceID)
   144  		if err != nil {
   145  			return view.Namespace{}, handleUpstreamError(err)
   146  		}
   147  		rs = rawRs.ToMutableRuleSet().Clone()
   148  		if err = rs.Revive(meta); err != nil {
   149  			return view.Namespace{}, handleUpstreamError(err)
   150  		}
   151  	}
   152  
   153  	if err = s.ruleStore.WriteAll(nss, rs); err != nil {
   154  		return view.Namespace{}, handleUpstreamError(err)
   155  	}
   156  
   157  	nss, err = s.ruleStore.ReadNamespaces()
   158  	if err != nil {
   159  		return view.Namespace{}, handleUpstreamError(err)
   160  	}
   161  
   162  	ns, err := nss.Namespace(namespaceID)
   163  	if err != nil {
   164  		return view.Namespace{}, r2.NewNotFoundError(fmt.Sprintf("namespace: %s does not exist", namespaceID))
   165  	}
   166  
   167  	// Get the latest view of the namespace.
   168  	nsView, err := ns.NamespaceView(len(ns.Snapshots()) - 1)
   169  	if err != nil {
   170  		return view.Namespace{}, handleUpstreamError(err)
   171  	}
   172  
   173  	return nsView, nil
   174  }
   175  
   176  func (s *store) DeleteNamespace(namespaceID string, uOpts r2store.UpdateOptions) error {
   177  	nss, err := s.ruleStore.ReadNamespaces()
   178  	if err != nil {
   179  		return handleUpstreamError(err)
   180  	}
   181  
   182  	rs, err := s.ruleStore.ReadRuleSet(namespaceID)
   183  	if err != nil {
   184  		return handleUpstreamError(err)
   185  	}
   186  
   187  	meta := s.newUpdateMeta(uOpts)
   188  	err = nss.DeleteNamespace(namespaceID, rs.Version(), meta)
   189  	if err != nil {
   190  		return handleUpstreamError(err)
   191  	}
   192  
   193  	mutable := rs.ToMutableRuleSet().Clone()
   194  	err = mutable.Delete(meta)
   195  	if err != nil {
   196  		return handleUpstreamError(err)
   197  	}
   198  
   199  	if err = s.ruleStore.WriteAll(nss, mutable); err != nil {
   200  		return handleUpstreamError(err)
   201  	}
   202  
   203  	return nil
   204  }
   205  
   206  func (s *store) FetchRuleSetSnapshot(namespaceID string) (view.RuleSet, error) {
   207  	rs, err := s.ruleStore.ReadRuleSet(namespaceID)
   208  	if err != nil {
   209  		return view.RuleSet{}, handleUpstreamError(err)
   210  	}
   211  	return rs.Latest()
   212  }
   213  
   214  func (s *store) FetchMappingRule(
   215  	namespaceID string,
   216  	mappingRuleID string,
   217  ) (view.MappingRule, error) {
   218  	ruleset, err := s.FetchRuleSetSnapshot(namespaceID)
   219  	if err != nil {
   220  		return view.MappingRule{}, err
   221  	}
   222  
   223  	for _, mr := range ruleset.MappingRules {
   224  		if mr.ID == mappingRuleID {
   225  			return mr, nil
   226  		}
   227  	}
   228  
   229  	return view.MappingRule{}, mappingRuleNotFoundError(namespaceID, mappingRuleID)
   230  }
   231  
   232  func (s *store) CreateMappingRule(
   233  	namespaceID string,
   234  	mrv view.MappingRule,
   235  	uOpts r2store.UpdateOptions,
   236  ) (view.MappingRule, error) {
   237  	rs, err := s.ruleStore.ReadRuleSet(namespaceID)
   238  	if err != nil {
   239  		return view.MappingRule{}, handleUpstreamError(err)
   240  	}
   241  
   242  	mutable := rs.ToMutableRuleSet().Clone()
   243  	newID, err := mutable.AddMappingRule(mrv, s.newUpdateMeta(uOpts))
   244  	if err != nil {
   245  		return view.MappingRule{}, handleUpstreamError(err)
   246  	}
   247  
   248  	err = s.ruleStore.WriteRuleSet(mutable)
   249  	if err != nil {
   250  		return view.MappingRule{}, handleUpstreamError(err)
   251  	}
   252  
   253  	return s.FetchMappingRule(namespaceID, newID)
   254  }
   255  
   256  func (s *store) UpdateMappingRule(
   257  	namespaceID string,
   258  	mappingRuleID string,
   259  	mrv view.MappingRule,
   260  	uOpts r2store.UpdateOptions,
   261  ) (view.MappingRule, error) {
   262  	rs, err := s.ruleStore.ReadRuleSet(namespaceID)
   263  	if err != nil {
   264  		return view.MappingRule{}, handleUpstreamError(err)
   265  	}
   266  
   267  	mutable := rs.ToMutableRuleSet().Clone()
   268  	err = mutable.UpdateMappingRule(mrv, s.newUpdateMeta(uOpts))
   269  	if err != nil {
   270  		return view.MappingRule{}, handleUpstreamError(err)
   271  	}
   272  
   273  	err = s.ruleStore.WriteRuleSet(mutable)
   274  	if err != nil {
   275  		return view.MappingRule{}, handleUpstreamError(err)
   276  	}
   277  
   278  	return s.FetchMappingRule(namespaceID, mappingRuleID)
   279  }
   280  
   281  func (s *store) DeleteMappingRule(
   282  	namespaceID string,
   283  	mappingRuleID string,
   284  	uOpts r2store.UpdateOptions,
   285  ) error {
   286  	rs, err := s.ruleStore.ReadRuleSet(namespaceID)
   287  	if err != nil {
   288  		return handleUpstreamError(err)
   289  	}
   290  
   291  	mutable := rs.ToMutableRuleSet().Clone()
   292  	err = mutable.DeleteMappingRule(mappingRuleID, s.newUpdateMeta(uOpts))
   293  	if err != nil {
   294  		return handleUpstreamError(err)
   295  	}
   296  
   297  	err = s.ruleStore.WriteRuleSet(mutable)
   298  	if err != nil {
   299  		return handleUpstreamError(err)
   300  	}
   301  
   302  	return nil
   303  }
   304  
   305  func (s *store) FetchMappingRuleHistory(
   306  	namespaceID string,
   307  	mappingRuleID string,
   308  ) ([]view.MappingRule, error) {
   309  	rs, err := s.ruleStore.ReadRuleSet(namespaceID)
   310  	if err != nil {
   311  		return nil, handleUpstreamError(err)
   312  	}
   313  
   314  	mrs, err := rs.MappingRules()
   315  	if err != nil {
   316  		return nil, handleUpstreamError(err)
   317  	}
   318  
   319  	for _, mappings := range mrs {
   320  		if len(mappings) > 0 && mappings[0].ID == mappingRuleID {
   321  			return mappings, nil
   322  		}
   323  	}
   324  
   325  	return nil, mappingRuleNotFoundError(namespaceID, mappingRuleID)
   326  }
   327  
   328  func (s *store) FetchRollupRule(
   329  	namespaceID string,
   330  	rollupRuleID string,
   331  ) (view.RollupRule, error) {
   332  	ruleset, err := s.FetchRuleSetSnapshot(namespaceID)
   333  	if err != nil {
   334  		return view.RollupRule{}, handleUpstreamError(err)
   335  	}
   336  
   337  	for _, rr := range ruleset.RollupRules {
   338  		if rr.ID == rollupRuleID {
   339  			return rr, nil
   340  		}
   341  	}
   342  
   343  	return view.RollupRule{}, rollupRuleNotFoundError(namespaceID, rollupRuleID)
   344  }
   345  
   346  func (s *store) CreateRollupRule(
   347  	namespaceID string,
   348  	rrv view.RollupRule,
   349  	uOpts r2store.UpdateOptions,
   350  ) (view.RollupRule, error) {
   351  	rs, err := s.ruleStore.ReadRuleSet(namespaceID)
   352  	if err != nil {
   353  		return view.RollupRule{}, handleUpstreamError(err)
   354  	}
   355  
   356  	mutable := rs.ToMutableRuleSet().Clone()
   357  	newID, err := mutable.AddRollupRule(rrv, s.newUpdateMeta(uOpts))
   358  	if err != nil {
   359  		return view.RollupRule{}, handleUpstreamError(err)
   360  	}
   361  
   362  	err = s.ruleStore.WriteRuleSet(mutable)
   363  	if err != nil {
   364  		return view.RollupRule{}, handleUpstreamError(err)
   365  	}
   366  
   367  	return s.FetchRollupRule(namespaceID, newID)
   368  }
   369  
   370  func (s *store) UpdateRollupRule(
   371  	namespaceID,
   372  	rollupRuleID string,
   373  	rrv view.RollupRule,
   374  	uOpts r2store.UpdateOptions,
   375  ) (view.RollupRule, error) {
   376  	rs, err := s.ruleStore.ReadRuleSet(namespaceID)
   377  	if err != nil {
   378  		return view.RollupRule{}, handleUpstreamError(err)
   379  	}
   380  
   381  	mutable := rs.ToMutableRuleSet().Clone()
   382  	err = mutable.UpdateRollupRule(rrv, s.newUpdateMeta(uOpts))
   383  	if err != nil {
   384  		return view.RollupRule{}, handleUpstreamError(err)
   385  	}
   386  
   387  	err = s.ruleStore.WriteRuleSet(mutable)
   388  	if err != nil {
   389  		return view.RollupRule{}, handleUpstreamError(err)
   390  	}
   391  
   392  	return s.FetchRollupRule(namespaceID, rollupRuleID)
   393  }
   394  
   395  func (s *store) DeleteRollupRule(
   396  	namespaceID string,
   397  	rollupRuleID string,
   398  	uOpts r2store.UpdateOptions,
   399  ) error {
   400  	rs, err := s.ruleStore.ReadRuleSet(namespaceID)
   401  	if err != nil {
   402  		return handleUpstreamError(err)
   403  	}
   404  
   405  	mutable := rs.ToMutableRuleSet().Clone()
   406  	err = mutable.DeleteRollupRule(rollupRuleID, s.newUpdateMeta(uOpts))
   407  	if err != nil {
   408  		return handleUpstreamError(err)
   409  	}
   410  
   411  	err = s.ruleStore.WriteRuleSet(mutable)
   412  	if err != nil {
   413  		return handleUpstreamError(err)
   414  	}
   415  
   416  	return nil
   417  }
   418  
   419  func (s *store) FetchRollupRuleHistory(
   420  	namespaceID string,
   421  	rollupRuleID string,
   422  ) ([]view.RollupRule, error) {
   423  	rs, err := s.ruleStore.ReadRuleSet(namespaceID)
   424  	if err != nil {
   425  		return nil, handleUpstreamError(err)
   426  	}
   427  
   428  	rrs, err := rs.RollupRules()
   429  	if err != nil {
   430  		return nil, handleUpstreamError(err)
   431  	}
   432  
   433  	for _, rollups := range rrs {
   434  		if len(rollups) > 0 && rollups[0].ID == rollupRuleID {
   435  			return rollups, nil
   436  		}
   437  	}
   438  
   439  	return nil, rollupRuleNotFoundError(namespaceID, rollupRuleID)
   440  }
   441  
   442  func (s *store) Close() { s.ruleStore.Close() }
   443  
   444  func (s *store) newUpdateMeta(uOpts r2store.UpdateOptions) rules.UpdateMetadata {
   445  	return s.updateHelper.NewUpdateMetadata(s.nowFn().UnixNano(), uOpts.Author())
   446  }
   447  
   448  func mappingRuleNotFoundError(namespaceID, mappingRuleID string) error {
   449  	return r2.NewNotFoundError(
   450  		fmt.Sprintf("mapping rule: %s doesn't exist in Namespace: %s",
   451  			mappingRuleID,
   452  			namespaceID,
   453  		),
   454  	)
   455  }
   456  
   457  func rollupRuleNotFoundError(namespaceID, rollupRuleID string) error {
   458  	return r2.NewNotFoundError(
   459  		fmt.Sprintf("rollup rule: %s doesn't exist in Namespace: %s",
   460  			rollupRuleID,
   461  			namespaceID,
   462  		),
   463  	)
   464  }
   465  
   466  func handleUpstreamError(err error) error {
   467  	if err == nil {
   468  		return nil
   469  	}
   470  
   471  	// If this is a contained error, extracts the inner error.
   472  	if e := xerrors.InnerError(err); e != nil {
   473  		err = e
   474  	}
   475  
   476  	switch err.(type) {
   477  	case merrors.InvalidInputError, merrors.StaleDataError:
   478  		return r2.NewConflictError(err.Error())
   479  	case merrors.ValidationError:
   480  		return r2.NewBadInputError(err.Error())
   481  	case merrors.NotFoundError:
   482  		return r2.NewNotFoundError(err.Error())
   483  	default:
   484  		return r2.NewInternalError(err.Error())
   485  	}
   486  }