mirror of https://github.com/grafana/grafana
dashboard: generate and include uid in dashboard model. #7883
parent
025a14ec24
commit
5b35c694dc
@ -0,0 +1,18 @@ |
||||
MIT License |
||||
|
||||
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. |
||||
@ -0,0 +1,362 @@ |
||||
// Copyright (c) 2016-2017. Oleg Sklyar & teris.io. All rights reserved.
|
||||
// See the LICENSE file in the project root for licensing information.
|
||||
|
||||
// Original algorithm:
|
||||
// Copyright (c) 2015 Dylan Greene, contributors: https://github.com/dylang/shortid.
|
||||
// MIT-license as found in the LICENSE file.
|
||||
|
||||
// Seed computation: based on The Central Randomizer 1.3
|
||||
// Copyright (c) 1997 Paul Houle (houle@msc.cornell.edu)
|
||||
|
||||
// Package shortid enables the generation of short, unique, non-sequential and by default URL friendly
|
||||
// Ids. The package is heavily inspired by the node.js https://github.com/dylang/shortid library.
|
||||
//
|
||||
// Id Length
|
||||
//
|
||||
// The standard Id length is 9 symbols when generated at a rate of 1 Id per millisecond,
|
||||
// occasionally it reaches 11 (at the rate of a few thousand Ids per millisecond) and very-very
|
||||
// rarely it can go beyond that during continuous generation at full throttle on high-performant
|
||||
// hardware. A test generating 500k Ids at full throttle on conventional hardware generated the
|
||||
// following Ids at the head and the tail (length > 9 is expected for this test):
|
||||
//
|
||||
// -NDveu-9Q
|
||||
// iNove6iQ9J
|
||||
// NVDve6-9Q
|
||||
// VVDvc6i99J
|
||||
// NVovc6-QQy
|
||||
// VVoveui9QC
|
||||
// ...
|
||||
// tFmGc6iQQs
|
||||
// KpTvcui99k
|
||||
// KFTGcuiQ9p
|
||||
// KFmGeu-Q9O
|
||||
// tFTvcu-QQt
|
||||
// tpTveu-99u
|
||||
//
|
||||
// Life span
|
||||
//
|
||||
// The package guarantees the generation of unique Ids with zero collisions for 34 years
|
||||
// (1/1/2016-1/1/2050) using the same worker Id within a single (although concurrent) application if
|
||||
// application restarts take longer than 1 millisecond. The package supports up to 32 works, all
|
||||
// providing unique sequences.
|
||||
//
|
||||
// Implementation details
|
||||
//
|
||||
// Although heavily inspired by the node.js shortid library this is
|
||||
// not a simple Go port. In addition it
|
||||
//
|
||||
// - is safe to concurrency;
|
||||
// - does not require any yearly version/epoch resets;
|
||||
// - provides stable Id size over a long period at the rate of 1ms;
|
||||
// - guarantees no collisions (due to guaranteed fixed size of Ids between milliseconds and because
|
||||
// multiple requests within the same ms lead to longer Ids with the prefix unique to the ms);
|
||||
// - supports 32 over 16 workers.
|
||||
//
|
||||
// The algorithm uses less randomness than the original node.js implementation, which permits to
|
||||
// extend the life span as well as reduce and guarantee the length. In general terms, each Id
|
||||
// has the following 3 pieces of information encoded: the millisecond (first 8 symbols), the worker
|
||||
// Id (9th symbol), running concurrent counter within the same millisecond, only if required, over
|
||||
// all remaining symbols. The element of randomness per symbol is 1/2 for the worker and the
|
||||
// millisecond and 0 for the counter. Here 0 means no randomness, i.e. every value is encoded using
|
||||
// a 64-base alphabet; 1/2 means one of two matching symbols of the supplied alphabet, 1/4 one of
|
||||
// four matching symbols. The original algorithm of the node.js module uses 1/4 throughout.
|
||||
//
|
||||
// All methods accepting the parameters that govern the randomness are exported and can be used
|
||||
// to directly implement an algorithm with e.g. more randomness, but with longer Ids and shorter
|
||||
// life spans.
|
||||
package shortid |
||||
|
||||
import ( |
||||
randc "crypto/rand" |
||||
"errors" |
||||
"fmt" |
||||
"math" |
||||
randm "math/rand" |
||||
"sync" |
||||
"sync/atomic" |
||||
"time" |
||||
"unsafe" |
||||
) |
||||
|
||||
// Version defined the library version.
|
||||
const Version = 1.1 |
||||
|
||||
// DefaultABC is the default URL-friendly alphabet.
|
||||
const DefaultABC = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-" |
||||
|
||||
// Abc represents a shuffled alphabet used to generate the Ids and provides methods to
|
||||
// encode data.
|
||||
type Abc struct { |
||||
alphabet []rune |
||||
} |
||||
|
||||
// Shortid type represents a short Id generator working with a given alphabet.
|
||||
type Shortid struct { |
||||
abc Abc |
||||
worker uint |
||||
epoch time.Time // ids can be generated for 34 years since this date
|
||||
ms uint // ms since epoch for the last id
|
||||
count uint // request count within the same ms
|
||||
mx sync.Mutex // locks access to ms and count
|
||||
} |
||||
|
||||
var shortid *Shortid |
||||
|
||||
func init() { |
||||
shortid = MustNew(0, DefaultABC, 1) |
||||
} |
||||
|
||||
// GetDefault retrieves the default short Id generator initialised with the default alphabet,
|
||||
// worker=0 and seed=1. The default can be overwritten using SetDefault.
|
||||
func GetDefault() *Shortid { |
||||
return (*Shortid)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&shortid)))) |
||||
} |
||||
|
||||
// SetDefault overwrites the default generator.
|
||||
func SetDefault(sid *Shortid) { |
||||
target := (*unsafe.Pointer)(unsafe.Pointer(&shortid)) |
||||
source := unsafe.Pointer(sid) |
||||
atomic.SwapPointer(target, source) |
||||
} |
||||
|
||||
// Generate generates an Id using the default generator.
|
||||
func Generate() (string, error) { |
||||
return shortid.Generate() |
||||
} |
||||
|
||||
// MustGenerate acts just like Generate, but panics instead of returning errors.
|
||||
func MustGenerate() string { |
||||
id, err := Generate() |
||||
if err == nil { |
||||
return id |
||||
} |
||||
panic(err) |
||||
} |
||||
|
||||
// New constructs an instance of the short Id generator for the given worker number [0,31], alphabet
|
||||
// (64 unique symbols) and seed value (to shuffle the alphabet). The worker number should be
|
||||
// different for multiple or distributed processes generating Ids into the same data space. The
|
||||
// seed, on contrary, should be identical.
|
||||
func New(worker uint8, alphabet string, seed uint64) (*Shortid, error) { |
||||
if worker > 31 { |
||||
return nil, errors.New("expected worker in the range [0,31]") |
||||
} |
||||
abc, err := NewAbc(alphabet, seed) |
||||
if err == nil { |
||||
sid := &Shortid{ |
||||
abc: abc, |
||||
worker: uint(worker), |
||||
epoch: time.Date(2016, time.January, 1, 0, 0, 0, 0, time.UTC), |
||||
ms: 0, |
||||
count: 0, |
||||
} |
||||
return sid, nil |
||||
} |
||||
return nil, err |
||||
} |
||||
|
||||
// MustNew acts just like New, but panics instead of returning errors.
|
||||
func MustNew(worker uint8, alphabet string, seed uint64) *Shortid { |
||||
sid, err := New(worker, alphabet, seed) |
||||
if err == nil { |
||||
return sid |
||||
} |
||||
panic(err) |
||||
} |
||||
|
||||
// Generate generates a new short Id.
|
||||
func (sid *Shortid) Generate() (string, error) { |
||||
return sid.GenerateInternal(nil, sid.epoch) |
||||
} |
||||
|
||||
// MustGenerate acts just like Generate, but panics instead of returning errors.
|
||||
func (sid *Shortid) MustGenerate() string { |
||||
id, err := sid.Generate() |
||||
if err == nil { |
||||
return id |
||||
} |
||||
panic(err) |
||||
} |
||||
|
||||
// GenerateInternal should only be used for testing purposes.
|
||||
func (sid *Shortid) GenerateInternal(tm *time.Time, epoch time.Time) (string, error) { |
||||
ms, count := sid.getMsAndCounter(tm, epoch) |
||||
idrunes := make([]rune, 9) |
||||
if tmp, err := sid.abc.Encode(ms, 8, 5); err == nil { |
||||
copy(idrunes, tmp) // first 8 symbols
|
||||
} else { |
||||
return "", err |
||||
} |
||||
if tmp, err := sid.abc.Encode(sid.worker, 1, 5); err == nil { |
||||
idrunes[8] = tmp[0] |
||||
} else { |
||||
return "", err |
||||
} |
||||
if count > 0 { |
||||
if countrunes, err := sid.abc.Encode(count, 0, 6); err == nil { |
||||
// only extend if really need it
|
||||
idrunes = append(idrunes, countrunes...) |
||||
} else { |
||||
return "", err |
||||
} |
||||
} |
||||
return string(idrunes), nil |
||||
} |
||||
|
||||
func (sid *Shortid) getMsAndCounter(tm *time.Time, epoch time.Time) (uint, uint) { |
||||
sid.mx.Lock() |
||||
defer sid.mx.Unlock() |
||||
var ms uint |
||||
if tm != nil { |
||||
ms = uint(tm.Sub(epoch).Nanoseconds() / 1000000) |
||||
} else { |
||||
ms = uint(time.Now().Sub(epoch).Nanoseconds() / 1000000) |
||||
} |
||||
if ms == sid.ms { |
||||
sid.count++ |
||||
} else { |
||||
sid.count = 0 |
||||
sid.ms = ms |
||||
} |
||||
return sid.ms, sid.count |
||||
} |
||||
|
||||
// String returns a string representation of the short Id generator.
|
||||
func (sid *Shortid) String() string { |
||||
return fmt.Sprintf("Shortid(worker=%v, epoch=%v, abc=%v)", sid.worker, sid.epoch, sid.abc) |
||||
} |
||||
|
||||
// Abc returns the instance of alphabet used for representing the Ids.
|
||||
func (sid *Shortid) Abc() Abc { |
||||
return sid.abc |
||||
} |
||||
|
||||
// Epoch returns the value of epoch used as the beginning of millisecond counting (normally
|
||||
// 2016-01-01 00:00:00 local time)
|
||||
func (sid *Shortid) Epoch() time.Time { |
||||
return sid.epoch |
||||
} |
||||
|
||||
// Worker returns the value of worker for this short Id generator.
|
||||
func (sid *Shortid) Worker() uint { |
||||
return sid.worker |
||||
} |
||||
|
||||
// NewAbc constructs a new instance of shuffled alphabet to be used for Id representation.
|
||||
func NewAbc(alphabet string, seed uint64) (Abc, error) { |
||||
runes := []rune(alphabet) |
||||
if len(runes) != len(DefaultABC) { |
||||
return Abc{}, fmt.Errorf("alphabet must contain %v unique characters", len(DefaultABC)) |
||||
} |
||||
if nonUnique(runes) { |
||||
return Abc{}, errors.New("alphabet must contain unique characters only") |
||||
} |
||||
abc := Abc{alphabet: nil} |
||||
abc.shuffle(alphabet, seed) |
||||
return abc, nil |
||||
} |
||||
|
||||
// MustNewAbc acts just like NewAbc, but panics instead of returning errors.
|
||||
func MustNewAbc(alphabet string, seed uint64) Abc { |
||||
res, err := NewAbc(alphabet, seed) |
||||
if err == nil { |
||||
return res |
||||
} |
||||
panic(err) |
||||
} |
||||
|
||||
func nonUnique(runes []rune) bool { |
||||
found := make(map[rune]struct{}) |
||||
for _, r := range runes { |
||||
if _, seen := found[r]; !seen { |
||||
found[r] = struct{}{} |
||||
} |
||||
} |
||||
return len(found) < len(runes) |
||||
} |
||||
|
||||
func (abc *Abc) shuffle(alphabet string, seed uint64) { |
||||
source := []rune(alphabet) |
||||
for len(source) > 1 { |
||||
seed = (seed*9301 + 49297) % 233280 |
||||
i := int(seed * uint64(len(source)) / 233280) |
||||
|
||||
abc.alphabet = append(abc.alphabet, source[i]) |
||||
source = append(source[:i], source[i+1:]...) |
||||
} |
||||
abc.alphabet = append(abc.alphabet, source[0]) |
||||
} |
||||
|
||||
// Encode encodes a given value into a slice of runes of length nsymbols. In case nsymbols==0, the
|
||||
// length of the result is automatically computed from data. Even if fewer symbols is required to
|
||||
// encode the data than nsymbols, all positions are used encoding 0 where required to guarantee
|
||||
// uniqueness in case further data is added to the sequence. The value of digits [4,6] represents
|
||||
// represents n in 2^n, which defines how much randomness flows into the algorithm: 4 -- every value
|
||||
// can be represented by 4 symbols in the alphabet (permitting at most 16 values), 5 -- every value
|
||||
// can be represented by 2 symbols in the alphabet (permitting at most 32 values), 6 -- every value
|
||||
// is represented by exactly 1 symbol with no randomness (permitting 64 values).
|
||||
func (abc *Abc) Encode(val, nsymbols, digits uint) ([]rune, error) { |
||||
if digits < 4 || 6 < digits { |
||||
return nil, fmt.Errorf("allowed digits range [4,6], found %v", digits) |
||||
} |
||||
|
||||
var computedSize uint = 1 |
||||
if val >= 1 { |
||||
computedSize = uint(math.Log2(float64(val)))/digits + 1 |
||||
} |
||||
if nsymbols == 0 { |
||||
nsymbols = computedSize |
||||
} else if nsymbols < computedSize { |
||||
return nil, fmt.Errorf("cannot accommodate data, need %v digits, got %v", computedSize, nsymbols) |
||||
} |
||||
|
||||
mask := 1<<digits - 1 |
||||
|
||||
random := make([]int, int(nsymbols)) |
||||
// no random component if digits == 6
|
||||
if digits < 6 { |
||||
copy(random, maskedRandomInts(len(random), 0x3f-mask)) |
||||
} |
||||
|
||||
res := make([]rune, int(nsymbols)) |
||||
for i := range res { |
||||
shift := digits * uint(i) |
||||
index := (int(val>>shift) & mask) | random[i] |
||||
res[i] = abc.alphabet[index] |
||||
} |
||||
return res, nil |
||||
} |
||||
|
||||
// MustEncode acts just like Encode, but panics instead of returning errors.
|
||||
func (abc *Abc) MustEncode(val, size, digits uint) []rune { |
||||
res, err := abc.Encode(val, size, digits) |
||||
if err == nil { |
||||
return res |
||||
} |
||||
panic(err) |
||||
} |
||||
|
||||
func maskedRandomInts(size, mask int) []int { |
||||
ints := make([]int, size) |
||||
bytes := make([]byte, size) |
||||
if _, err := randc.Read(bytes); err == nil { |
||||
for i, b := range bytes { |
||||
ints[i] = int(b) & mask |
||||
} |
||||
} else { |
||||
for i := range ints { |
||||
ints[i] = randm.Intn(0xff) & mask |
||||
} |
||||
} |
||||
return ints |
||||
} |
||||
|
||||
// String returns a string representation of the Abc instance.
|
||||
func (abc Abc) String() string { |
||||
return fmt.Sprintf("Abc{alphabet='%v')", abc.Alphabet()) |
||||
} |
||||
|
||||
// Alphabet returns the alphabet used as an immutable string.
|
||||
func (abc Abc) Alphabet() string { |
||||
return string(abc.alphabet) |
||||
} |
||||
Loading…
Reference in new issue