Skip to content
This repository has been archived by the owner on Oct 17, 2018. It is now read-only.

Commit

Permalink
Store change history in each version
Browse files Browse the repository at this point in the history
  • Loading branch information
xichen2020 committed Apr 5, 2017
1 parent 396457d commit 9082932
Show file tree
Hide file tree
Showing 10 changed files with 789 additions and 481 deletions.
8 changes: 4 additions & 4 deletions generated/proto/rule.proto
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ message RollupTarget {

message RollupRule {
string name = 1;
map<string,string> tag_filters = 2;
bool tombstoned = 2;
int64 cutover_time = 3;
bool tombstoned = 4;
map<string,string> tag_filters = 4;
repeated RollupTarget targets = 5;
}

Expand All @@ -42,8 +42,8 @@ message RuleSet {
int64 last_updated_at = 4;
bool tombstoned = 5;
int64 cutover_time = 6;
repeated MappingRuleChanges mapping_rules = 7;
repeated RollupRuleChanges rollup_rules = 8;
repeated MappingRuleChanges mapping_rule_changes = 7;
repeated RollupRuleChanges rollup_rule_changes = 8;
}

message Namespace {
Expand Down
101 changes: 50 additions & 51 deletions generated/proto/schema/rule.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

59 changes: 49 additions & 10 deletions rules/mapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ package rules

import (
"errors"
"time"

"github.com/m3db/m3metrics/filters"
"github.com/m3db/m3metrics/generated/proto/schema"
Expand All @@ -36,17 +37,20 @@ var (
// mappingRule defines a rule such that if a metric matches the provided filters,
// it is aggregated and retained under the provided set of policies.
type mappingRule struct {
name string
tombstoned bool
cutoverTimeNs int64
filter filters.Filter
policies []policy.Policy // defines how the metrics should be aggregated and retained
name string
tombstoned bool
cutoverNs int64
filter filters.Filter
policies []policy.Policy
}

func newMappingRule(
r *schema.MappingRule,
iterfn filters.NewSortedTagIteratorFn,
) (*mappingRule, error) {
if r == nil {
return nil, errNilMappingRuleSchema
}
policies, err := policy.NewPoliciesFromSchema(r.Policies)
if err != nil {
return nil, err
Expand All @@ -56,11 +60,11 @@ func newMappingRule(
return nil, err
}
return &mappingRule{
name: r.Name,
tombstoned: r.Tombstoned,
cutoverTimeNs: r.CutoverTime,
filter: filter,
policies: policies,
name: r.Name,
tombstoned: r.Tombstoned,
cutoverNs: r.CutoverTime,
filter: filter,
policies: policies,
}, nil
}

Expand All @@ -74,6 +78,9 @@ func newMappingRuleChanges(
mc *schema.MappingRuleChanges,
iterfn filters.NewSortedTagIteratorFn,
) (*mappingRuleChanges, error) {
if mc == nil {
return nil, errNilMappingRuleChangesSchema
}
changes := make([]*mappingRule, 0, len(mc.Changes))
for i := 0; i < len(mc.Changes); i++ {
mr, err := newMappingRule(mc.Changes[i], iterfn)
Expand All @@ -87,3 +94,35 @@ func newMappingRuleChanges(
changes: changes,
}, nil
}

// ActiveRule returns the latest rule whose cutover time is earlier than or
// equal to t, or nil if not found.
func (mc *mappingRuleChanges) ActiveRule(t time.Time) *mappingRule {
idx := mc.activeIndex(t)
if idx < 0 {
return nil
}
return mc.changes[idx]
}

// ActiveRules returns the rule that's in effect at time t and all future
// rules after time t.
func (mc *mappingRuleChanges) ActiveRules(t time.Time) *mappingRuleChanges {
idx := mc.activeIndex(t)
// If there are no rules that are currently in effect, it means either all
// rules are in the future, or there are no rules.
if idx < 0 {
return mc
}
return &mappingRuleChanges{uuid: mc.uuid, changes: mc.changes[idx:]}
}

func (mc *mappingRuleChanges) activeIndex(t time.Time) int {
target := t.UnixNano()
idx := 0
for idx < len(mc.changes) && mc.changes[idx].cutoverNs <= target {
idx++
}
idx--
return idx
}
94 changes: 94 additions & 0 deletions rules/namespace.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// Copyright (c) 2017 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package rules

import (
"errors"

"github.com/m3db/m3metrics/generated/proto/schema"
)

var (
emptyNamespace Namespace
emptyNamespaces Namespaces

errNilNamespaceSchema = errors.New("nil namespace schema")
errNilNamespacesSchema = errors.New("nil namespaces schema")
)

// Namespace is a logical isolation unit for which rules are defined.
type Namespace struct {
name string
tombstoned bool
expireAtNs int64
}

// newNameSpace creates a new namespace.
func newNameSpace(namespace *schema.Namespace) (Namespace, error) {
if namespace == nil {
return emptyNamespace, errNilNamespaceSchema
}
return Namespace{
name: namespace.Name,
tombstoned: namespace.Tombstoned,
expireAtNs: namespace.ExpireAt,
}, nil
}

// Name is the name of the namespace.
func (n *Namespace) Name() string { return n.name }

// Tombstoned determines whether the namespace has been tombstoned.
func (n *Namespace) Tombstoned() bool { return n.tombstoned }

// ExpireAtNs determines when the namespace will be expired.
func (n *Namespace) ExpireAtNs() int64 { return n.expireAtNs }

// Namespaces store the list of namespaces for which rules are defined.
type Namespaces struct {
version int
namespaces []Namespace
}

// NewNamespaces creates new namespaces.
func NewNamespaces(version int, namespaces *schema.Namespaces) (Namespaces, error) {
if namespaces == nil {
return emptyNamespaces, errNilNamespacesSchema
}
nss := make([]Namespace, 0, len(namespaces.Namespaces))
for _, namespace := range namespaces.Namespaces {
ns, err := newNameSpace(namespace)
if err != nil {
return emptyNamespaces, err
}
nss = append(nss, ns)
}
return Namespaces{
version: version,
namespaces: nss,
}, nil
}

// Namespaces returns the list of namespaces.
func (nss Namespaces) Namespaces() []Namespace { return nss.namespaces }

// Version returns the namespaces version.
func (nss Namespaces) Version() int { return nss.version }
Loading

0 comments on commit 9082932

Please sign in to comment.