Initial commit

This commit is contained in:
Donny
2019-04-22 20:46:32 +08:00
commit 49ab8aadd1
25441 changed files with 4055000 additions and 0 deletions

30
vendor/github.com/jtolds/gls/BUILD.bazel generated vendored Normal file
View File

@@ -0,0 +1,30 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"context.go",
"gen_sym.go",
"gid.go",
"id_pool.go",
"stack_tags.go",
"stack_tags_main.go",
],
importmap = "go-common/vendor/github.com/jtolds/gls",
importpath = "github.com/jtolds/gls",
visibility = ["//visibility:public"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

18
vendor/github.com/jtolds/gls/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,18 @@
Copyright (c) 2013, Space Monkey, 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.

89
vendor/github.com/jtolds/gls/README.md generated vendored Normal file
View File

@@ -0,0 +1,89 @@
gls
===
Goroutine local storage
### IMPORTANT NOTE ###
It is my duty to point you to https://blog.golang.org/context, which is how
Google solves all of the problems you'd perhaps consider using this package
for at scale.
One downside to Google's approach is that *all* of your functions must have
a new first argument, but after clearing that hurdle everything else is much
better.
If you aren't interested in this warning, read on.
### Huhwaht? Why? ###
Every so often, a thread shows up on the
[golang-nuts](https://groups.google.com/d/forum/golang-nuts) asking for some
form of goroutine-local-storage, or some kind of goroutine id, or some kind of
context. There are a few valid use cases for goroutine-local-storage, one of
the most prominent being log line context. One poster was interested in being
able to log an HTTP request context id in every log line in the same goroutine
as the incoming HTTP request, without having to change every library and
function call he was interested in logging.
This would be pretty useful. Provided that you could get some kind of
goroutine-local-storage, you could call
[log.SetOutput](http://golang.org/pkg/log/#SetOutput) with your own logging
writer that checks goroutine-local-storage for some context information and
adds that context to your log lines.
But alas, Andrew Gerrand's typically diplomatic answer to the question of
goroutine-local variables was:
> We wouldn't even be having this discussion if thread local storage wasn't
> useful. But every feature comes at a cost, and in my opinion the cost of
> threadlocals far outweighs their benefits. They're just not a good fit for
> Go.
So, yeah, that makes sense. That's a pretty good reason for why the language
won't support a specific and (relatively) unuseful feature that requires some
runtime changes, just for the sake of a little bit of log improvement.
But does Go require runtime changes?
### How it works ###
Go has pretty fantastic introspective and reflective features, but one thing Go
doesn't give you is any kind of access to the stack pointer, or frame pointer,
or goroutine id, or anything contextual about your current stack. It gives you
access to your list of callers, but only along with program counters, which are
fixed at compile time.
But it does give you the stack.
So, we define 16 special functions and embed base-16 tags into the stack using
the call order of those 16 functions. Then, we can read our tags back out of
the stack looking at the callers list.
We then use these tags as an index into a traditional map for implementing
this library.
### What are people saying? ###
"Wow, that's horrifying."
"This is the most terrible thing I have seen in a very long time."
"Where is it getting a context from? Is this serializing all the requests?
What the heck is the client being bound to? What are these tags? Why does he
need callers? Oh god no. No no no."
### Docs ###
Please see the docs at http://godoc.org/github.com/jtolds/gls
### Related ###
If you're okay relying on the string format of the current runtime stacktrace
including a unique goroutine id (not guaranteed by the spec or anything, but
very unlikely to change within a Go release), you might be able to squeeze
out a bit more performance by using this similar library, inspired by some
code Brad Fitzpatrick wrote for debugging his HTTP/2 library:
https://github.com/tylerb/gls (in contrast, jtolds/gls doesn't require
any knowledge of the string format of the runtime stacktrace, which
probably adds unnecessary overhead).

153
vendor/github.com/jtolds/gls/context.go generated vendored Normal file
View File

@@ -0,0 +1,153 @@
// Package gls implements goroutine-local storage.
package gls
import (
"sync"
)
var (
mgrRegistry = make(map[*ContextManager]bool)
mgrRegistryMtx sync.RWMutex
)
// Values is simply a map of key types to value types. Used by SetValues to
// set multiple values at once.
type Values map[interface{}]interface{}
// ContextManager is the main entrypoint for interacting with
// Goroutine-local-storage. You can have multiple independent ContextManagers
// at any given time. ContextManagers are usually declared globally for a given
// class of context variables. You should use NewContextManager for
// construction.
type ContextManager struct {
mtx sync.Mutex
values map[uint]Values
}
// NewContextManager returns a brand new ContextManager. It also registers the
// new ContextManager in the ContextManager registry which is used by the Go
// method. ContextManagers are typically defined globally at package scope.
func NewContextManager() *ContextManager {
mgr := &ContextManager{values: make(map[uint]Values)}
mgrRegistryMtx.Lock()
defer mgrRegistryMtx.Unlock()
mgrRegistry[mgr] = true
return mgr
}
// Unregister removes a ContextManager from the global registry, used by the
// Go method. Only intended for use when you're completely done with a
// ContextManager. Use of Unregister at all is rare.
func (m *ContextManager) Unregister() {
mgrRegistryMtx.Lock()
defer mgrRegistryMtx.Unlock()
delete(mgrRegistry, m)
}
// SetValues takes a collection of values and a function to call for those
// values to be set in. Anything further down the stack will have the set
// values available through GetValue. SetValues will add new values or replace
// existing values of the same key and will not mutate or change values for
// previous stack frames.
// SetValues is slow (makes a copy of all current and new values for the new
// gls-context) in order to reduce the amount of lookups GetValue requires.
func (m *ContextManager) SetValues(new_values Values, context_call func()) {
if len(new_values) == 0 {
context_call()
return
}
mutated_keys := make([]interface{}, 0, len(new_values))
mutated_vals := make(Values, len(new_values))
EnsureGoroutineId(func(gid uint) {
m.mtx.Lock()
state, found := m.values[gid]
if !found {
state = make(Values, len(new_values))
m.values[gid] = state
}
m.mtx.Unlock()
for key, new_val := range new_values {
mutated_keys = append(mutated_keys, key)
if old_val, ok := state[key]; ok {
mutated_vals[key] = old_val
}
state[key] = new_val
}
defer func() {
if !found {
m.mtx.Lock()
delete(m.values, gid)
m.mtx.Unlock()
return
}
for _, key := range mutated_keys {
if val, ok := mutated_vals[key]; ok {
state[key] = val
} else {
delete(state, key)
}
}
}()
context_call()
})
}
// GetValue will return a previously set value, provided that the value was set
// by SetValues somewhere higher up the stack. If the value is not found, ok
// will be false.
func (m *ContextManager) GetValue(key interface{}) (
value interface{}, ok bool) {
gid, ok := GetGoroutineId()
if !ok {
return nil, false
}
m.mtx.Lock()
state, found := m.values[gid]
m.mtx.Unlock()
if !found {
return nil, false
}
value, ok = state[key]
return value, ok
}
func (m *ContextManager) getValues() Values {
gid, ok := GetGoroutineId()
if !ok {
return nil
}
m.mtx.Lock()
state, _ := m.values[gid]
m.mtx.Unlock()
return state
}
// Go preserves ContextManager values and Goroutine-local-storage across new
// goroutine invocations. The Go method makes a copy of all existing values on
// all registered context managers and makes sure they are still set after
// kicking off the provided function in a new goroutine. If you don't use this
// Go method instead of the standard 'go' keyword, you will lose values in
// ContextManagers, as goroutines have brand new stacks.
func Go(cb func()) {
mgrRegistryMtx.RLock()
defer mgrRegistryMtx.RUnlock()
for mgr := range mgrRegistry {
values := mgr.getValues()
if len(values) > 0 {
cb = func(mgr *ContextManager, cb func()) func() {
return func() { mgr.SetValues(values, cb) }
}(mgr, cb)
}
}
go cb()
}

21
vendor/github.com/jtolds/gls/gen_sym.go generated vendored Normal file
View File

@@ -0,0 +1,21 @@
package gls
import (
"sync"
)
var (
keyMtx sync.Mutex
keyCounter uint64
)
// ContextKey is a throwaway value you can use as a key to a ContextManager
type ContextKey struct{ id uint64 }
// GenSym will return a brand new, never-before-used ContextKey
func GenSym() ContextKey {
keyMtx.Lock()
defer keyMtx.Unlock()
keyCounter += 1
return ContextKey{id: keyCounter}
}

25
vendor/github.com/jtolds/gls/gid.go generated vendored Normal file
View File

@@ -0,0 +1,25 @@
package gls
var (
stackTagPool = &idPool{}
)
// Will return this goroutine's identifier if set. If you always need a
// goroutine identifier, you should use EnsureGoroutineId which will make one
// if there isn't one already.
func GetGoroutineId() (gid uint, ok bool) {
return readStackTag()
}
// Will call cb with the current goroutine identifier. If one hasn't already
// been generated, one will be created and set first. The goroutine identifier
// might be invalid after cb returns.
func EnsureGoroutineId(cb func(gid uint)) {
if gid, ok := readStackTag(); ok {
cb(gid)
return
}
gid := stackTagPool.Acquire()
defer stackTagPool.Release(gid)
addStackTag(gid, func() { cb(gid) })
}

34
vendor/github.com/jtolds/gls/id_pool.go generated vendored Normal file
View File

@@ -0,0 +1,34 @@
package gls
// though this could probably be better at keeping ids smaller, the goal of
// this class is to keep a registry of the smallest unique integer ids
// per-process possible
import (
"sync"
)
type idPool struct {
mtx sync.Mutex
released []uint
max_id uint
}
func (p *idPool) Acquire() (id uint) {
p.mtx.Lock()
defer p.mtx.Unlock()
if len(p.released) > 0 {
id = p.released[len(p.released)-1]
p.released = p.released[:len(p.released)-1]
return id
}
id = p.max_id
p.max_id++
return id
}
func (p *idPool) Release(id uint) {
p.mtx.Lock()
defer p.mtx.Unlock()
p.released = append(p.released, id)
}

113
vendor/github.com/jtolds/gls/stack_tags.go generated vendored Normal file
View File

@@ -0,0 +1,113 @@
package gls
// so, basically, we're going to encode integer tags in base-16 on the stack
const (
bitWidth = 4
stackBatchSize = 16
)
var (
pc_lookup = make(map[uintptr]int8, 17)
mark_lookup [16]func(uint, func())
)
func init() {
setEntries := func(f func(uint, func()), v int8) {
var ptr uintptr
f(0, func() {
ptr = findPtr()
})
pc_lookup[ptr] = v
if v >= 0 {
mark_lookup[v] = f
}
}
setEntries(github_com_jtolds_gls_markS, -0x1)
setEntries(github_com_jtolds_gls_mark0, 0x0)
setEntries(github_com_jtolds_gls_mark1, 0x1)
setEntries(github_com_jtolds_gls_mark2, 0x2)
setEntries(github_com_jtolds_gls_mark3, 0x3)
setEntries(github_com_jtolds_gls_mark4, 0x4)
setEntries(github_com_jtolds_gls_mark5, 0x5)
setEntries(github_com_jtolds_gls_mark6, 0x6)
setEntries(github_com_jtolds_gls_mark7, 0x7)
setEntries(github_com_jtolds_gls_mark8, 0x8)
setEntries(github_com_jtolds_gls_mark9, 0x9)
setEntries(github_com_jtolds_gls_markA, 0xa)
setEntries(github_com_jtolds_gls_markB, 0xb)
setEntries(github_com_jtolds_gls_markC, 0xc)
setEntries(github_com_jtolds_gls_markD, 0xd)
setEntries(github_com_jtolds_gls_markE, 0xe)
setEntries(github_com_jtolds_gls_markF, 0xf)
}
func addStackTag(tag uint, context_call func()) {
if context_call == nil {
return
}
github_com_jtolds_gls_markS(tag, context_call)
}
// these private methods are named this horrendous name so gopherjs support
// is easier. it shouldn't add any runtime cost in non-js builds.
func github_com_jtolds_gls_markS(tag uint, cb func()) { _m(tag, cb) }
func github_com_jtolds_gls_mark0(tag uint, cb func()) { _m(tag, cb) }
func github_com_jtolds_gls_mark1(tag uint, cb func()) { _m(tag, cb) }
func github_com_jtolds_gls_mark2(tag uint, cb func()) { _m(tag, cb) }
func github_com_jtolds_gls_mark3(tag uint, cb func()) { _m(tag, cb) }
func github_com_jtolds_gls_mark4(tag uint, cb func()) { _m(tag, cb) }
func github_com_jtolds_gls_mark5(tag uint, cb func()) { _m(tag, cb) }
func github_com_jtolds_gls_mark6(tag uint, cb func()) { _m(tag, cb) }
func github_com_jtolds_gls_mark7(tag uint, cb func()) { _m(tag, cb) }
func github_com_jtolds_gls_mark8(tag uint, cb func()) { _m(tag, cb) }
func github_com_jtolds_gls_mark9(tag uint, cb func()) { _m(tag, cb) }
func github_com_jtolds_gls_markA(tag uint, cb func()) { _m(tag, cb) }
func github_com_jtolds_gls_markB(tag uint, cb func()) { _m(tag, cb) }
func github_com_jtolds_gls_markC(tag uint, cb func()) { _m(tag, cb) }
func github_com_jtolds_gls_markD(tag uint, cb func()) { _m(tag, cb) }
func github_com_jtolds_gls_markE(tag uint, cb func()) { _m(tag, cb) }
func github_com_jtolds_gls_markF(tag uint, cb func()) { _m(tag, cb) }
func _m(tag_remainder uint, cb func()) {
if tag_remainder == 0 {
cb()
} else {
mark_lookup[tag_remainder&0xf](tag_remainder>>bitWidth, cb)
}
}
func readStackTag() (tag uint, ok bool) {
var current_tag uint
offset := 0
for {
batch, next_offset := getStack(offset, stackBatchSize)
for _, pc := range batch {
val, ok := pc_lookup[pc]
if !ok {
continue
}
if val < 0 {
return current_tag, true
}
current_tag <<= bitWidth
current_tag += uint(val)
}
if next_offset == 0 {
break
}
offset = next_offset
}
return 0, false
}
func (m *ContextManager) preventInlining() {
// dunno if findPtr or getStack are likely to get inlined in a future release
// of go, but if they are inlined and their callers are inlined, that could
// hork some things. let's do our best to explain to the compiler that we
// really don't want those two functions inlined by saying they could change
// at any time. assumes preventInlining doesn't get compiled out.
// this whole thing is probably overkill.
findPtr = m.values[0][0].(func() uintptr)
getStack = m.values[0][1].(func(int, int) ([]uintptr, int))
}

75
vendor/github.com/jtolds/gls/stack_tags_js.go generated vendored Normal file
View File

@@ -0,0 +1,75 @@
// +build js
package gls
// This file is used for GopherJS builds, which don't have normal runtime
// stack trace support
import (
"strconv"
"strings"
"github.com/gopherjs/gopherjs/js"
)
const (
jsFuncNamePrefix = "github_com_jtolds_gls_mark"
)
func jsMarkStack() (f []uintptr) {
lines := strings.Split(
js.Global.Get("Error").New().Get("stack").String(), "\n")
f = make([]uintptr, 0, len(lines))
for i, line := range lines {
line = strings.TrimSpace(line)
if line == "" {
continue
}
if i == 0 {
if line != "Error" {
panic("didn't understand js stack trace")
}
continue
}
fields := strings.Fields(line)
if len(fields) < 2 || fields[0] != "at" {
panic("didn't understand js stack trace")
}
pos := strings.Index(fields[1], jsFuncNamePrefix)
if pos < 0 {
continue
}
pos += len(jsFuncNamePrefix)
if pos >= len(fields[1]) {
panic("didn't understand js stack trace")
}
char := string(fields[1][pos])
switch char {
case "S":
f = append(f, uintptr(0))
default:
val, err := strconv.ParseUint(char, 16, 8)
if err != nil {
panic("didn't understand js stack trace")
}
f = append(f, uintptr(val)+1)
}
}
return f
}
// variables to prevent inlining
var (
findPtr = func() uintptr {
funcs := jsMarkStack()
if len(funcs) == 0 {
panic("failed to find function pointer")
}
return funcs[0]
}
getStack = func(offset, amount int) (stack []uintptr, next_offset int) {
return jsMarkStack(), 0
}
)

30
vendor/github.com/jtolds/gls/stack_tags_main.go generated vendored Normal file
View File

@@ -0,0 +1,30 @@
// +build !js
package gls
// This file is used for standard Go builds, which have the expected runtime
// support
import (
"runtime"
)
var (
findPtr = func() uintptr {
var pc [1]uintptr
n := runtime.Callers(4, pc[:])
if n != 1 {
panic("failed to find function pointer")
}
return pc[0]
}
getStack = func(offset, amount int) (stack []uintptr, next_offset int) {
stack = make([]uintptr, amount)
stack = stack[:runtime.Callers(offset, stack)]
if len(stack) < amount {
return stack, 0
}
return stack, offset + len(stack)
}
)