├── .codecov.yml
├── .excludecoverage
├── .excludefmt
├── .excludelint
├── .excludemetalint
├── .gitignore
├── .gitmodules
├── .metalinter.json
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── README.md
├── checked
├── bytes.go
├── bytes_test.go
├── checked_mock.go
├── debug.go
├── debug_test.go
├── ref.go
├── ref_test.go
└── types.go
├── clock
├── config.go
├── options.go
├── types.go
└── types_test.go
├── close
├── close.go
└── close_test.go
├── config
├── config.go
├── config_test.go
├── example_test.go
├── hostid
│ ├── hostid.go
│ └── hostid_test.go
├── listenaddress
│ ├── listenaddress.go
│ └── listenaddress_test.go
├── pooling.go
├── pooling_test.go
└── testdata
│ └── conf.yaml
├── context
├── cancel.go
├── cancel_test.go
├── context.go
├── context_test.go
├── finalizeables_arraypool_gen.go
├── options.go
├── pool.go
├── pool_test.go
└── types.go
├── debug
├── mutex.go
└── mutex_test.go
├── doc.go
├── errors
├── errors.go
├── errors_test.go
└── example_test.go
├── generated-source-files.mk
├── generated
└── mocks
│ └── generate.go
├── generics
├── arraypool
│ ├── pool.go
│ └── pool_test.go
├── hashmap
│ ├── byteskey
│ │ ├── map_gen.go
│ │ ├── map_pool_test.go
│ │ └── new_map.go
│ ├── idkey
│ │ ├── map_gen.go
│ │ ├── map_pool_test.go
│ │ └── new_map.go
│ ├── map.go
│ └── map_test.go
└── leakcheckpool
│ ├── pool.go
│ └── pool_test.go
├── glide.lock
├── glide.yaml
├── hash
├── doc.go
└── jump
│ ├── doc.go
│ ├── example_test.go
│ ├── jump.go
│ └── jump_test.go
├── ident
├── bytes_id.go
├── id_matcher.go
├── ident_mock.go
├── identifier.go
├── identifier_pool.go
├── identifier_pool_test.go
├── identifier_test.go
├── iterator.go
├── iterator_test.go
├── tag.go
├── tag_arraypool_gen.go
├── tag_iterator.go
├── tag_iterator_matcher.go
├── tag_iterator_matcher_test.go
├── tag_iterator_test.go
├── tag_matcher.go
├── tags_test.go
├── testutil
│ ├── tags_convert.go
│ └── tags_convert_test.go
└── types.go
├── instrument
├── build.go
├── build_test.go
├── config.go
├── extended.go
├── invariant.go
├── invariant_test.go
├── methods.go
├── options.go
├── process.go
├── process_test.go
├── reporter.go
├── sanitize.go
└── types.go
├── log
├── config.go
├── config_test.go
├── logger.go
└── logger_test.go
├── net
├── example_test.go
├── server.go
└── server_test.go
├── opentracing
├── context.go
├── context_test.go
├── tracing.go
└── tracing_test.go
├── pool
├── bucketized.go
├── bytes.go
├── bytes_test.go
├── checked_bytes.go
├── checked_bytes_test.go
├── checked_object.go
├── checked_object_test.go
├── config.go
├── config_test.go
├── example_test.go
├── floats.go
├── floats_test.go
├── object.go
├── object_test.go
├── options.go
├── pool_mock.go
└── types.go
├── pprof
├── pprof.go
└── pprof_test.go
├── process
├── process_linux.go
└── process_notlinux.go
├── resource
└── types.go
├── retry
├── config.go
├── config_test.go
├── example_test.go
├── options.go
├── retry.go
├── retry_test.go
└── types.go
├── sampler
├── sampler.go
└── sampler_test.go
├── server
├── config.go
├── config_test.go
├── example_test.go
├── options.go
├── server.go
└── server_test.go
├── sync
├── example_test.go
├── options.go
├── pooled_worker_pool.go
├── pooled_worker_pool_test.go
├── types.go
├── worker_pool.go
└── worker_pool_test.go
├── tcp
└── tcp.go
├── test
├── matcher.go
└── reporter.go
├── time
├── duration.go
├── duration_test.go
├── matcher.go
├── matcher_test.go
├── range.go
├── range_iter.go
├── range_iter_test.go
├── range_test.go
├── ranges.go
├── ranges_test.go
├── time.go
├── time_test.go
├── unit.go
├── unit_test.go
├── unix_nano.go
└── unix_nano_test.go
├── unsafe
├── bytes.go
├── bytes_test.go
├── string.go
└── string_test.go
└── watch
├── options.go
├── source.go
├── source_test.go
├── value.go
├── value_test.go
├── watch.go
└── watch_test.go
/.codecov.yml:
--------------------------------------------------------------------------------
1 | coverage:
2 | precision: 2
3 | round: down
4 | range: "70...100"
5 |
6 | status:
7 | project:
8 | default: on
9 | patch:
10 | default: on
11 | changes:
12 | default: on
13 |
14 | comment:
15 | layout: "header, reach, diff, flags, footer"
16 | behavior: default
17 | require_changes: no
18 | require_base: no
19 | require_head: yes
20 |
--------------------------------------------------------------------------------
/.excludecoverage:
--------------------------------------------------------------------------------
1 | _mock.go
2 | generated/
3 | vendor/
4 | integration/
5 | testgen/
6 |
--------------------------------------------------------------------------------
/.excludefmt:
--------------------------------------------------------------------------------
1 | (vendor/)
2 | (proto/)
3 | (gen-go/)
4 | (mocks/)
5 | (.pb.go)
--------------------------------------------------------------------------------
/.excludelint:
--------------------------------------------------------------------------------
1 | (vendor/)
2 | (proto/)
3 | (gen-go/)
4 | (mocks/)
5 | (.pb.go)
6 | (_mock.go)
7 | (_gen.go)
8 |
--------------------------------------------------------------------------------
/.excludemetalint:
--------------------------------------------------------------------------------
1 | vendor/
2 | generated/
3 | _mock.go
4 | _gen.go
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.out
2 | *.test
3 | *.xml
4 | *.swp
5 | .idea/
6 | .vscode/
7 | *.iml
8 | *.ipr
9 | *.iws
10 | *.cov
11 | *.html
12 | test.log
13 |
14 | # Build binaries
15 | bin/
16 |
17 | # Debug binaries
18 | debug.test
19 |
20 | # Glide
21 | vendor/
22 |
23 | # Generated source
24 | codegen/
25 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule ".ci"]
2 | path = .ci
3 | url = https://github.com/m3db/ci-scripts.git
4 |
--------------------------------------------------------------------------------
/.metalinter.json:
--------------------------------------------------------------------------------
1 | {
2 | "Linters": {
3 | "badtime": {
4 | "Command": "badtime",
5 | "Pattern": "PATH:LINE:COL:MESSAGE"
6 | }
7 | },
8 | "Enable":
9 | [ "golint"
10 | , "deadcode"
11 | , "varcheck"
12 | , "structcheck"
13 | , "goconst"
14 | , "ineffassign"
15 | , "unconvert"
16 | , "misspell"
17 | , "unparam"
18 | , "megacheck"
19 | , "badtime" ],
20 | "Deadline": "3m",
21 | "EnableGC": true
22 | }
23 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | Changelog
2 | =========
3 |
4 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Contributing
2 | ============
3 |
4 | We'd love your help making M3DB great!
5 |
6 | ## Getting Started
7 |
8 | M3DB uses Go vendoring to manage dependencies.
9 | To get started:
10 |
11 | ```bash
12 | git submodule update --init --recursive
13 | make test
14 | ```
15 |
16 | ## Making A Change
17 |
18 | *Before making any significant changes, please [open an
19 | issue](https://github.com/m3db/m3x/issues).* Discussing your proposed
20 | changes ahead of time will make the contribution process smooth for everyone.
21 |
22 | Once we've discussed your changes and you've got your code ready, make sure
23 | that tests are passing (`make test` or `make cover`) and open your PR! Your
24 | pull request is most likely to be accepted if it:
25 |
26 | * Includes tests for new functionality.
27 | * Follows the guidelines in [Effective
28 | Go](https://golang.org/doc/effective_go.html) and the [Go team's common code
29 | review comments](https://github.com/golang/go/wiki/CodeReviewComments).
30 | * Has a [good commit
31 | message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
32 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | SELF_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
2 | include $(SELF_DIR)/.ci/common.mk
3 | include $(SELF_DIR)/generated-source-files.mk
4 |
5 | SHELL=/bin/bash -o pipefail
6 |
7 | html_report := coverage.html
8 | test := .ci/test-cover.sh
9 | convert-test-data := .ci/convert-test-data.sh
10 | coverage_xml := coverage.xml
11 | junit_xml := junit.xml
12 | test_log := test.log
13 | metalint_check := .ci/metalint.sh
14 | metalint_config := .metalinter.json
15 | metalint_exclude := .excludemetalint
16 | license_dir := .ci/uber-licence
17 | license_node_modules := $(license_dir)/node_modules
18 | gopath_prefix := $(GOPATH)/src
19 | vendor_prefix := vendor
20 | auto_gen := .ci/auto-gen.sh
21 | m3x_package := github.com/m3db/m3x
22 | mockgen_package := github.com/golang/mock/mockgen
23 | mocks_output_dir := generated/mocks/mocks
24 | mocks_rules_dir := generated/mocks
25 |
26 | BUILD := $(abspath ./bin)
27 | LINUX_AMD64_ENV := GOOS=linux GOARCH=amd64 CGO_ENABLED=0
28 |
29 | .PHONY: setup
30 | setup:
31 | mkdir -p $(BUILD)
32 |
33 | .PHONY: metalint
34 | metalint: install-metalinter install-linter-badtime
35 | @($(metalint_check) $(metalint_config) $(metalint_exclude) && echo "metalinted successfully!") || (echo "metalinter failed" && exit 1)
36 |
37 | .PHONY: test-internal
38 | test-internal:
39 | @which go-junit-report > /dev/null || go get -u github.com/sectioneight/go-junit-report
40 | $(test) $(coverfile) | tee $(test_log)
41 |
42 | .PHONY: test-xml
43 | test-xml: test-internal
44 | go-junit-report < $(test_log) > $(junit_xml)
45 | gocov convert $(coverfile) | gocov-xml > $(coverage_xml)
46 | @$(convert-test-data) $(coverage_xml)
47 | @rm $(coverfile) &> /dev/null
48 |
49 | .PHONY: test
50 | test: test-internal
51 | gocov convert $(coverfile) | gocov report
52 |
53 | .PHONY: testhtml
54 | testhtml: test-internal
55 | gocov convert $(coverfile) | gocov-html > $(html_report) && open $(html_report)
56 | @rm -f $(test_log) &> /dev/null
57 |
58 | .PHONY: test-ci-unit
59 | test-ci-unit: test-base
60 | $(codecov_push) -f $(coverfile)
61 |
62 | .PHONY: install-license-bin
63 | install-license-bin:
64 | @echo Installing node modules
65 | [ -d $(license_node_modules) ] || ( \
66 | git submodule update --init --recursive && \
67 | cd $(license_dir) && npm install \
68 | )
69 |
70 | .PHONY: install-mockgen
71 | install-mockgen:
72 | @echo Installing mockgen
73 | @which mockgen >/dev/null || (make install-vendor && \
74 | rm -rf $(gopath_prefix)/$(mockgen_package) && \
75 | cp -r $(vendor_prefix)/$(mockgen_package) $(gopath_prefix)/$(mockgen_package) && \
76 | go install $(mockgen_package) \
77 | )
78 |
79 | .PHONY: mock-gen
80 | mock-gen: install-mockgen install-license-bin install-util-mockclean
81 | @echo Generating mocks
82 | PACKAGE=$(m3x_package) $(auto_gen) $(mocks_output_dir) $(mocks_rules_dir)
83 |
84 | .PHONY: all-gen
85 | all-gen: mock-gen genny-all
86 |
87 | .PHONY: clean
88 | clean:
89 | @rm -f *.html *.xml *.out *.test
90 |
91 | .PHONY: all
92 | all: metalint test-ci-unit test-genny-all
93 | @echo Made all successfully
94 |
95 | .DEFAULT_GOAL := all
96 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Migration Warning
2 | =================
3 | This repository has been migrated to github.com/m3db/m3. It's contents can be found at github.com/m3db/m3/src/x. Follow along there for updates. This repository is marked archived, and will no longer receive any updates.
4 |
5 | # M3X [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov]
6 |
7 | Common utility code shared by all M3DB components.
8 |
9 |
10 |
11 | This project is released under the [Apache License, Version 2.0](LICENSE).
12 |
13 | [doc-img]: https://godoc.org/github.com/m3db/m3x?status.svg
14 | [doc]: https://godoc.org/github.com/m3db/m3x
15 | [ci-img]: https://travis-ci.org/m3db/m3x.svg?branch=master
16 | [ci]: https://travis-ci.org/m3db/m3x
17 | [cov-img]: https://coveralls.io/repos/m3db/m3x/badge.svg?branch=master&service=github
18 | [cov]: https://coveralls.io/github/m3db/m3x?branch=master
19 |
20 | # Development
21 |
22 | ## Setup
23 |
24 | 1. Clone the repo into your $GOPATH
25 | 2. Run `git submodule update --init --recursive`
26 | 3. Run `glide install -v` - [Install Glide first if you don't have it](https://github.com/Masterminds/glide)
27 | 4. Run `make test` and make sure everything passes
28 | 5. Write new code and tests
29 |
--------------------------------------------------------------------------------
/checked/bytes_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 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 checked
22 |
23 | import (
24 | "testing"
25 |
26 | "github.com/stretchr/testify/assert"
27 | )
28 |
29 | func TestBytes(t *testing.T) {
30 | raw := make([]byte, 3, 5)
31 | copy(raw, []byte{'a', 'b', 'c'})
32 |
33 | var onFinalize BytesFinalizerFn
34 | finalizer := BytesFinalizerFn(func(finalizing Bytes) {
35 | onFinalize(finalizing)
36 | })
37 |
38 | b := NewBytes(raw, NewBytesOptions().SetFinalizer(finalizer))
39 | b.IncRef()
40 |
41 | assert.Equal(t, []byte("abc"), b.Bytes())
42 | assert.Equal(t, 3, b.Len())
43 | assert.Equal(t, 5, b.Cap())
44 |
45 | b.Append('d')
46 | b.AppendAll([]byte{'e', 'f'})
47 |
48 | assert.Equal(t, []byte("abcdef"), b.Bytes())
49 | assert.Equal(t, 6, b.Len())
50 |
51 | b.Resize(4)
52 | assert.Equal(t, []byte("abcd"), b.Bytes())
53 | assert.Equal(t, 4, b.Len())
54 |
55 | b.Reset([]byte{'x', 'y', 'z'})
56 | assert.Equal(t, []byte("xyz"), b.Bytes())
57 | assert.Equal(t, 3, b.Len())
58 |
59 | b.DecRef()
60 |
61 | finalizerCalls := 0
62 | onFinalize = func(finalizing Bytes) {
63 | // Ensure closing the ref we created
64 | assert.Equal(t, b, finalizing)
65 | finalizing.IncRef()
66 | assert.Equal(t, []byte("xyz"), finalizing.Bytes())
67 | finalizing.DecRef()
68 | finalizerCalls++
69 | }
70 |
71 | b.Finalize()
72 | assert.Equal(t, 1, finalizerCalls)
73 | }
74 |
--------------------------------------------------------------------------------
/clock/config.go:
--------------------------------------------------------------------------------
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 clock
22 |
23 | import "time"
24 |
25 | // Configuration configures clock options.
26 | type Configuration struct {
27 | // MaxPositiveSkew is the maximum positive clock skew
28 | // with regard to a reference clock.
29 | MaxPositiveSkew time.Duration `yaml:"maxPositiveSkew"`
30 |
31 | // MaxNegativeSkew is the maximum negative clock skew
32 | // with regard to a reference clock.
33 | MaxNegativeSkew time.Duration `yaml:"maxNegativeSkew"`
34 | }
35 |
36 | // NewOptions creates a new set of options.
37 | func (c Configuration) NewOptions() Options {
38 | opts := NewOptions()
39 | if c.MaxPositiveSkew != 0 {
40 | opts = opts.SetMaxPositiveSkew(c.MaxPositiveSkew)
41 | }
42 | if c.MaxNegativeSkew != 0 {
43 | opts = opts.SetMaxNegativeSkew(c.MaxNegativeSkew)
44 | }
45 | return opts
46 | }
47 |
--------------------------------------------------------------------------------
/clock/options.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 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 clock
22 |
23 | import (
24 | "time"
25 | )
26 |
27 | type options struct {
28 | nowFn NowFn
29 | maxPositiveSkew time.Duration
30 | maxNegativeSkew time.Duration
31 | }
32 |
33 | // NewOptions creates new clock options.
34 | func NewOptions() Options {
35 | return &options{
36 | nowFn: time.Now,
37 | }
38 | }
39 |
40 | func (o *options) SetNowFn(value NowFn) Options {
41 | opts := *o
42 | opts.nowFn = value
43 | return &opts
44 | }
45 |
46 | func (o *options) NowFn() NowFn {
47 | return o.nowFn
48 | }
49 |
50 | func (o *options) SetMaxPositiveSkew(value time.Duration) Options {
51 | opts := *o
52 | opts.maxPositiveSkew = value
53 | return &opts
54 | }
55 |
56 | func (o *options) MaxPositiveSkew() time.Duration {
57 | return o.maxPositiveSkew
58 | }
59 |
60 | func (o *options) SetMaxNegativeSkew(value time.Duration) Options {
61 | opts := *o
62 | opts.maxNegativeSkew = value
63 | return &opts
64 | }
65 |
66 | func (o *options) MaxNegativeSkew() time.Duration {
67 | return o.maxNegativeSkew
68 | }
69 |
--------------------------------------------------------------------------------
/clock/types.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 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 clock implements facilities for working with wall clock time.
22 | package clock
23 |
24 | import (
25 | "time"
26 | )
27 |
28 | // NowFn is the function supplied to determine "now".
29 | type NowFn func() time.Time
30 |
31 | // Options represents the options for the clock.
32 | type Options interface {
33 | // SetNowFn sets the NowFn.
34 | SetNowFn(value NowFn) Options
35 |
36 | // NowFn returns the NowFn.
37 | NowFn() NowFn
38 |
39 | // SetMaxPositiveSkew sets the maximum positive clock skew
40 | // with regard to a reference clock.
41 | SetMaxPositiveSkew(value time.Duration) Options
42 |
43 | // MaxPositiveSkew returns the maximum positive clock skew
44 | // with regard to a reference clock.
45 | MaxPositiveSkew() time.Duration
46 |
47 | // SetMaxNegativeSkew sets the maximum negative clock skew
48 | // with regard to a reference clock.
49 | SetMaxNegativeSkew(value time.Duration) Options
50 |
51 | // MaxNegativeSkew returns the maximum negative clock skew
52 | // with regard to a reference clock.
53 | MaxNegativeSkew() time.Duration
54 | }
55 |
56 | // ConditionFn specifies a predicate to check.
57 | type ConditionFn func() bool
58 |
59 | // WaitUntil returns true if the condition specified evaluated to
60 | // true before the timeout, false otherwise.
61 | func WaitUntil(fn ConditionFn, timeout time.Duration) bool {
62 | deadline := time.Now().Add(timeout)
63 | for time.Now().Before(deadline) {
64 | if fn() {
65 | return true
66 | }
67 | time.Sleep(100 * time.Millisecond)
68 | }
69 | return false
70 | }
71 |
--------------------------------------------------------------------------------
/clock/types_test.go:
--------------------------------------------------------------------------------
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 clock
22 |
23 | import (
24 | "testing"
25 | "time"
26 |
27 | "github.com/stretchr/testify/require"
28 | )
29 |
30 | func TestAlwaysFalseConditionFn(t *testing.T) {
31 | falseConditionFn := func() bool { return false }
32 | require.False(t, WaitUntil(falseConditionFn, time.Second))
33 | }
34 |
35 | func TestAlwaysTrueConditionFn(t *testing.T) {
36 | trueConditionFn := func() bool { return true }
37 | require.True(t, WaitUntil(trueConditionFn, time.Second))
38 | }
39 |
40 | func TestDeadlineExpiredConditionFn(t *testing.T) {
41 | count := 0
42 | delayedConditionFn := func() bool {
43 | count++
44 | return count > 4
45 | }
46 | require.True(t, WaitUntil(delayedConditionFn, time.Second))
47 | }
48 |
--------------------------------------------------------------------------------
/close/close.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 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 close provides utilities for closing resources.
22 | package close
23 |
24 | import (
25 | "errors"
26 | "io"
27 | )
28 |
29 | var (
30 | // ErrNotCloseable is returned when trying to close a resource
31 | // that does not conform to a closeable interface.
32 | ErrNotCloseable = errors.New("not a closeable resource")
33 | )
34 |
35 | // Closer is a resource that can be closed.
36 | type Closer interface {
37 | io.Closer
38 | }
39 |
40 | // SimpleCloser is a resource that can be closed without returning a result.
41 | type SimpleCloser interface {
42 | Close()
43 | }
44 |
45 | // TryClose attempts to close a resource, the resource is expected to
46 | // implement either Closeable or CloseableResult.
47 | func TryClose(r interface{}) error {
48 | if r, ok := r.(Closer); ok {
49 | return r.Close()
50 | }
51 | if r, ok := r.(SimpleCloser); ok {
52 | r.Close()
53 | return nil
54 | }
55 | return ErrNotCloseable
56 | }
57 |
--------------------------------------------------------------------------------
/close/close_test.go:
--------------------------------------------------------------------------------
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 close
22 |
23 | import (
24 | "errors"
25 | "testing"
26 |
27 | "github.com/stretchr/testify/assert"
28 | )
29 |
30 | func TestTryClose(t *testing.T) {
31 | tests := []struct {
32 | input interface{}
33 | expectErr bool
34 | }{
35 | {
36 | input: &closer{returnErr: false},
37 | expectErr: false,
38 | },
39 | {
40 | input: &closer{returnErr: true},
41 | expectErr: true,
42 | },
43 | {
44 | input: &simpleCloser{},
45 | expectErr: false,
46 | },
47 | {
48 | input: &nonCloser{},
49 | expectErr: true,
50 | },
51 | }
52 |
53 | for _, test := range tests {
54 | err := TryClose(test.input)
55 | if test.expectErr {
56 | assert.Error(t, err)
57 | continue
58 | }
59 | assert.NoError(t, err)
60 | }
61 | }
62 |
63 | type closer struct {
64 | returnErr bool
65 | }
66 |
67 | func (c *closer) Close() error {
68 | if c.returnErr {
69 | return errors.New("")
70 | }
71 | return nil
72 | }
73 |
74 | type simpleCloser struct{}
75 |
76 | func (c *simpleCloser) Close() {}
77 |
78 | type nonCloser struct{}
79 |
--------------------------------------------------------------------------------
/config/config.go:
--------------------------------------------------------------------------------
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 config provides utilities for loading configuration files.
22 | package config
23 |
24 | import (
25 | "errors"
26 | "io/ioutil"
27 |
28 | validator "gopkg.in/validator.v2"
29 | yaml "gopkg.in/yaml.v2"
30 | )
31 |
32 | var errNoFilesToLoad = errors.New("attempt to load config with no files")
33 |
34 | // Options is an options set used when parsing config.
35 | type Options struct {
36 | DisableUnmarshalStrict bool
37 | DisableValidate bool
38 | }
39 |
40 | // LoadFile loads a config from a file.
41 | func LoadFile(config interface{}, file string, opts Options) error {
42 | return LoadFiles(config, []string{file}, opts)
43 | }
44 |
45 | // LoadFiles loads a config from list of files. If value for a property is
46 | // present in multiple files, the value from the last file will be applied.
47 | // Validation is done after merging all values.
48 | func LoadFiles(config interface{}, files []string, opts Options) error {
49 | if len(files) == 0 {
50 | return errNoFilesToLoad
51 | }
52 | for _, name := range files {
53 | data, err := ioutil.ReadFile(name)
54 | if err != nil {
55 | return err
56 | }
57 | unmarshal := yaml.UnmarshalStrict
58 | if opts.DisableUnmarshalStrict {
59 | unmarshal = yaml.Unmarshal
60 | }
61 | if err := unmarshal(data, config); err != nil {
62 | return err
63 | }
64 | }
65 | if opts.DisableValidate {
66 | return nil
67 | }
68 | return validator.Validate(config)
69 | }
70 |
--------------------------------------------------------------------------------
/config/example_test.go:
--------------------------------------------------------------------------------
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 config_test
22 |
23 | import (
24 | "fmt"
25 | "log"
26 |
27 | "github.com/m3db/m3x/config"
28 | )
29 |
30 | type configuration struct {
31 | ListenAddress string `yaml:"listenAddress" validate:"nonzero"`
32 | }
33 |
34 | func ExampleLoadFile() {
35 | var cfg configuration
36 | file := "testdata/conf.yaml"
37 | if err := config.LoadFile(&cfg, file, config.Options{}); err != nil {
38 | log.Fatal(err)
39 | }
40 | fmt.Printf("listenAddress: %s\n", cfg.ListenAddress)
41 | // Output: listenAddress: 0.0.0.0:8392
42 | }
43 |
--------------------------------------------------------------------------------
/config/pooling.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 config
22 |
23 | import "github.com/m3db/m3x/sync"
24 |
25 | const (
26 | defaultWorkerPoolStaticSize = 4096
27 | defaultGrowKillProbability = 0.001
28 | )
29 |
30 | // WorkerPoolPolicy specifies the policy for the worker pool.
31 | type WorkerPoolPolicy struct {
32 | // Determines if the worker pool automatically grows to capacity.
33 | GrowOnDemand bool `yaml:"grow"`
34 |
35 | // Size for static pools, initial size for dynamically growing pools.
36 | Size int `yaml:"size"`
37 |
38 | // The number of shards for the pool.
39 | NumShards int64 `yaml:"shards"`
40 |
41 | // The probablility that a worker is killed after completing the task.
42 | KillWorkerProbability float64 `yaml:"killProbability" validate:"min=0.0,max=1.0"`
43 | }
44 |
45 | // Options converts the worker pool policy to options, providing
46 | // the options, as well as the default size for the worker pool.
47 | func (w WorkerPoolPolicy) Options() (sync.PooledWorkerPoolOptions, int) {
48 | opts := sync.NewPooledWorkerPoolOptions()
49 | grow := w.GrowOnDemand
50 | opts = opts.SetGrowOnDemand(grow)
51 | if w.KillWorkerProbability != 0 {
52 | opts = opts.SetKillWorkerProbability(w.KillWorkerProbability)
53 | } else if grow {
54 | // NB: if using a growing pool, default kill probability is too low, causing
55 | // the pool to quickly grow out of control. Use a higher default kill probability
56 | opts = opts.SetKillWorkerProbability(defaultGrowKillProbability)
57 | }
58 |
59 | if w.NumShards != 0 {
60 | opts = opts.SetNumShards(w.NumShards)
61 | }
62 |
63 | if w.Size == 0 {
64 | if grow {
65 | w.Size = int(opts.NumShards())
66 | } else {
67 | w.Size = defaultWorkerPoolStaticSize
68 | }
69 | }
70 |
71 | return opts, w.Size
72 | }
73 |
--------------------------------------------------------------------------------
/config/pooling_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 | package config
21 |
22 | import (
23 | "testing"
24 |
25 | "github.com/m3db/m3x/sync"
26 | "github.com/stretchr/testify/assert"
27 | )
28 |
29 | func TestWorkerPoolPolicyConvertsToOptionsDefault(t *testing.T) {
30 | wpp := WorkerPoolPolicy{}
31 | opts, size := wpp.Options()
32 | defaultOpts := sync.NewPooledWorkerPoolOptions()
33 |
34 | assert.False(t, opts.GrowOnDemand())
35 | assert.Equal(t, defaultOpts.NumShards(), opts.NumShards())
36 | assert.Equal(t, defaultOpts.KillWorkerProbability(), opts.KillWorkerProbability())
37 | assert.Equal(t, defaultWorkerPoolStaticSize, size)
38 | }
39 |
40 | func TestWorkerPoolPolicyConvertsToOptionsDefaultGrow(t *testing.T) {
41 | wpp := WorkerPoolPolicy{GrowOnDemand: true}
42 | opts, size := wpp.Options()
43 | defaultOpts := sync.NewPooledWorkerPoolOptions()
44 |
45 | assert.True(t, opts.GrowOnDemand())
46 | assert.Equal(t, defaultOpts.NumShards(), opts.NumShards())
47 | assert.Equal(t, defaultGrowKillProbability, opts.KillWorkerProbability())
48 | assert.Equal(t, opts.NumShards(), int64(size))
49 | }
50 |
51 | func TestWorkerPoolPolicyConvertsToOptions(t *testing.T) {
52 | wpp := WorkerPoolPolicy{
53 | GrowOnDemand: true,
54 | Size: 100,
55 | NumShards: 200,
56 | KillWorkerProbability: 0.5,
57 | }
58 | opts, size := wpp.Options()
59 | assert.True(t, opts.GrowOnDemand())
60 | assert.Equal(t, int64(200), opts.NumShards())
61 | assert.Equal(t, 0.5, opts.KillWorkerProbability())
62 | assert.Equal(t, 100, size)
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/config/testdata/conf.yaml:
--------------------------------------------------------------------------------
1 | listenAddress: "0.0.0.0:8392"
2 |
--------------------------------------------------------------------------------
/context/cancel.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 context
22 |
23 | import "sync/atomic"
24 |
25 | type cancellable struct {
26 | cancelled int32
27 | }
28 |
29 | // NewCancellable creates a new cancellable object
30 | func NewCancellable() Cancellable {
31 | return &cancellable{}
32 | }
33 |
34 | func (c *cancellable) IsCancelled() bool { return atomic.LoadInt32(&c.cancelled) == 1 }
35 | func (c *cancellable) Cancel() { atomic.StoreInt32(&c.cancelled, 1) }
36 | func (c *cancellable) Reset() { atomic.StoreInt32(&c.cancelled, 0) }
37 |
38 | // NoOpCancellable is a no-op cancellable
39 | var noOpCancellable Cancellable = cancellableNoOp{}
40 |
41 | type cancellableNoOp struct{}
42 |
43 | // NewNoOpCanncellable returns a no-op cancellable
44 | func NewNoOpCanncellable() Cancellable { return noOpCancellable }
45 | func (c cancellableNoOp) IsCancelled() bool { return false }
46 | func (c cancellableNoOp) Cancel() {}
47 | func (c cancellableNoOp) Reset() {}
48 |
--------------------------------------------------------------------------------
/context/cancel_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 context
22 |
23 | import (
24 | "testing"
25 |
26 | "github.com/stretchr/testify/require"
27 | )
28 |
29 | func TestCancellable(t *testing.T) {
30 | c := NewCancellable()
31 | require.False(t, c.IsCancelled())
32 |
33 | c.Cancel()
34 | require.True(t, c.IsCancelled())
35 |
36 | c.Reset()
37 | require.False(t, c.IsCancelled())
38 | }
39 |
40 | func TestNoOpCancellable(t *testing.T) {
41 | c := NewNoOpCanncellable()
42 | require.False(t, c.IsCancelled())
43 |
44 | c.Cancel()
45 | require.False(t, c.IsCancelled())
46 |
47 | c.Reset()
48 | require.False(t, c.IsCancelled())
49 | }
50 |
--------------------------------------------------------------------------------
/context/options.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 context
22 |
23 | import "github.com/m3db/m3x/pool"
24 |
25 | const (
26 | defaultInitFinalizersCap = 4
27 | defaultMaxFinalizersCap = 1 << 16
28 | )
29 |
30 | type opts struct {
31 | contextPoolOpts pool.ObjectPoolOptions
32 | finalizerPoolOpts pool.ObjectPoolOptions
33 | maxPooledFinalizerCap int
34 | initPooledFinalizerCap int
35 | }
36 |
37 | // NewOptions returns a new Options object.
38 | func NewOptions() Options {
39 | return &opts{
40 | contextPoolOpts: pool.NewObjectPoolOptions(),
41 | finalizerPoolOpts: pool.NewObjectPoolOptions(),
42 | maxPooledFinalizerCap: defaultMaxFinalizersCap,
43 | initPooledFinalizerCap: defaultInitFinalizersCap,
44 | }
45 | }
46 |
47 | func (o *opts) SetContextPoolOptions(po pool.ObjectPoolOptions) Options {
48 | opts := *o
49 | opts.contextPoolOpts = po
50 | return &opts
51 | }
52 |
53 | func (o *opts) ContextPoolOptions() pool.ObjectPoolOptions {
54 | return o.contextPoolOpts
55 | }
56 |
57 | func (o *opts) SetFinalizerPoolOptions(po pool.ObjectPoolOptions) Options {
58 | opts := *o
59 | opts.finalizerPoolOpts = po
60 | return &opts
61 | }
62 |
63 | func (o *opts) FinalizerPoolOptions() pool.ObjectPoolOptions {
64 | return o.finalizerPoolOpts
65 | }
66 |
67 | func (o *opts) SetMaxPooledFinalizerCapacity(max int) Options {
68 | opts := *o
69 | opts.maxPooledFinalizerCap = max
70 | return &opts
71 | }
72 |
73 | func (o *opts) MaxPooledFinalizerCapacity() int {
74 | return o.maxPooledFinalizerCap
75 | }
76 |
77 | func (o *opts) SetInitPooledFinalizerCapacity(init int) Options {
78 | opts := *o
79 | opts.initPooledFinalizerCap = init
80 | return &opts
81 | }
82 |
83 | func (o *opts) InitPooledFinalizerCapacity() int {
84 | return o.initPooledFinalizerCap
85 | }
86 |
--------------------------------------------------------------------------------
/context/pool.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 context
22 |
23 | import (
24 | "github.com/m3db/m3x/pool"
25 | )
26 |
27 | type poolOfContexts struct {
28 | ctxPool pool.ObjectPool
29 | finalizersPool finalizeablesArrayPool
30 | }
31 |
32 | // NewPool creates a new context pool.
33 | func NewPool(opts Options) Pool {
34 | p := &poolOfContexts{
35 | ctxPool: pool.NewObjectPool(opts.ContextPoolOptions()),
36 | finalizersPool: newFinalizeablesArrayPool(finalizeablesArrayPoolOpts{
37 | Capacity: opts.InitPooledFinalizerCapacity(),
38 | MaxCapacity: opts.MaxPooledFinalizerCapacity(),
39 | Options: opts.FinalizerPoolOptions(),
40 | }),
41 | }
42 |
43 | p.finalizersPool.Init()
44 | p.ctxPool.Init(func() interface{} {
45 | return newPooledContext(p)
46 | })
47 |
48 | return p
49 | }
50 |
51 | func (p *poolOfContexts) Get() Context {
52 | return p.ctxPool.Get().(Context)
53 | }
54 |
55 | func (p *poolOfContexts) Put(context Context) {
56 | p.ctxPool.Put(context)
57 | }
58 |
59 | func (p *poolOfContexts) getFinalizeables() []finalizeable {
60 | return p.finalizersPool.Get()
61 | }
62 |
63 | func (p *poolOfContexts) putFinalizeables(finalizeables []finalizeable) {
64 | p.finalizersPool.Put(finalizeables)
65 | }
66 |
--------------------------------------------------------------------------------
/context/pool_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 context
22 |
23 | import (
24 | "testing"
25 |
26 | "github.com/m3db/m3x/resource"
27 |
28 | "github.com/stretchr/testify/assert"
29 | )
30 |
31 | func TestContextPool(t *testing.T) {
32 | opts := NewOptions().SetInitPooledFinalizerCapacity(0)
33 | pool := NewPool(opts)
34 |
35 | ctx := pool.Get()
36 | finalizeCalled := false
37 | ctx.RegisterFinalizer(resource.FinalizerFn(func() {
38 | finalizeCalled = true
39 | }))
40 | ctx.BlockingClose()
41 | assert.True(t, finalizeCalled)
42 | }
43 |
--------------------------------------------------------------------------------
/debug/mutex_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 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 debug
22 |
23 | import (
24 | "strings"
25 | "sync"
26 | "sync/atomic"
27 | "testing"
28 | "time"
29 |
30 | "github.com/stretchr/testify/require"
31 | )
32 |
33 | type captureIOWriter struct {
34 | callback func(p []byte)
35 | }
36 |
37 | func (b *captureIOWriter) Write(p []byte) (int, error) {
38 | b.callback(p)
39 | return len(p), nil
40 | }
41 |
42 | func TestRWMutexReportEvery(t *testing.T) {
43 | var (
44 | captured string
45 | wg sync.WaitGroup
46 | doneWg sync.WaitGroup
47 | )
48 |
49 | doneWg.Add(1)
50 | wg.Add(1)
51 | hasCaptured := false
52 | mutex := &RWMutex{Name: "lock", Writer: &captureIOWriter{callback: func(p []byte) {
53 | if !hasCaptured {
54 | hasCaptured = true
55 | captured = string(p)
56 | wg.Done()
57 | }
58 | }}}
59 |
60 | // Create a writer that holds onto the lock
61 | go func() {
62 | mutex.Lock()
63 | doneWg.Wait()
64 | mutex.Unlock()
65 | }()
66 |
67 | // Wait for writer to appear
68 | if atomic.LoadInt64(&mutex.writers) != 1 {
69 | time.Sleep(time.Millisecond)
70 | }
71 |
72 | // Create a few pending writers and readers
73 | for i := 0; i < 3; i++ {
74 | // nolint: megacheck
75 | go func() {
76 | mutex.Lock()
77 | mutex.Unlock()
78 | }()
79 | }
80 | for i := 0; i < 10; i++ {
81 | // nolint: megacheck
82 | go func() {
83 | mutex.RLock()
84 | mutex.RUnlock()
85 | }()
86 | }
87 |
88 | // Start reporter
89 | reporter := mutex.ReportEvery(time.Millisecond)
90 |
91 | // Wait for report
92 | wg.Wait()
93 |
94 | // Close the reporter
95 | reporter.Close()
96 |
97 | // Unlock the active writer
98 | doneWg.Done()
99 |
100 | // Match that the data is as expected
101 | firstExpect := "debug.RWMutex[lock]: writers 1 (pending 3) readers 10, stack: goroutine"
102 | require.True(t, len(captured) > len(firstExpect))
103 | require.Equal(t, firstExpect, captured[:len(firstExpect)])
104 |
105 | // Fuzzy match that the stack looks correct
106 | require.True(t, strings.Contains(captured, "TestRWMutexReportEvery.func"))
107 | }
108 |
--------------------------------------------------------------------------------
/doc.go:
--------------------------------------------------------------------------------
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 m3x implements common utility functions and experimental components.
22 | package m3x
23 |
--------------------------------------------------------------------------------
/errors/example_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 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 errors_test
22 |
23 | import (
24 | "fmt"
25 | "strings"
26 |
27 | "github.com/m3db/m3x/errors"
28 | )
29 |
30 | func ExampleMultiError() {
31 | multiErr := errors.NewMultiError()
32 |
33 | for i := 0; i < 3; i++ {
34 | // Perform some work which may fail.
35 | err := fmt.Errorf("error %d", i)
36 |
37 | if err != nil {
38 | // Add returns a new MultiError.
39 | multiErr = multiErr.Add(err)
40 | }
41 | }
42 |
43 | if err := multiErr.FinalError(); err != nil {
44 | msg := strings.Replace(err.Error(), "\n", "; ", -1)
45 | fmt.Println(msg)
46 | }
47 |
48 | if err := multiErr.LastError(); err != nil {
49 | fmt.Println(err)
50 | }
51 |
52 | // Output:
53 | // error 0; error 1; error 2
54 | // error 2
55 | }
56 |
--------------------------------------------------------------------------------
/generated/mocks/generate.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 | //go:generate sh -c "mockgen -package=ident $PACKAGE/ident ID,TagIterator | mockclean -pkg $PACKAGE/ident -out $GOPATH/src/$PACKAGE/ident/ident_mock.go"
22 | //go:generate sh -c "mockgen -package=checked $PACKAGE/checked Bytes | mockclean -pkg $PACKAGE/checked -out $GOPATH/src/$PACKAGE/checked/checked_mock.go"
23 | //go:generate sh -c "mockgen -package=pool $PACKAGE/pool CheckedBytesPool,BytesPool | mockclean -pkg $PACKAGE/pool -out $GOPATH/src/$PACKAGE/pool/pool_mock.go"
24 |
25 | package generated
26 |
--------------------------------------------------------------------------------
/generics/arraypool/pool_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 arraypool
22 |
23 | import (
24 | "testing"
25 |
26 | "github.com/m3db/m3x/pool"
27 |
28 | "github.com/stretchr/testify/require"
29 | )
30 |
31 | func TestArrayPool(t *testing.T) {
32 | pool := newElemArrayPool(elemArrayPoolOpts{
33 | Capacity: 10,
34 | Options: pool.NewObjectPoolOptions(),
35 | })
36 | require.NotNil(t, pool)
37 |
38 | pool.Init()
39 | e := pool.Get()
40 | require.NotNil(t, e)
41 | pool.Put(e)
42 | }
43 |
44 | func TestArrayPoolPut(t *testing.T) {
45 | var original []elemType
46 | finalizeFn := func(arr []elemType) []elemType {
47 | require.Equal(t, original, arr)
48 | return arr
49 | }
50 | pool := newElemArrayPool(elemArrayPoolOpts{
51 | Capacity: 10,
52 | Options: pool.NewObjectPoolOptions(),
53 | FinalizeFn: finalizeFn,
54 | })
55 | require.NotNil(t, pool)
56 | pool.Init()
57 | original = pool.Get()
58 | require.NotNil(t, original)
59 | pool.Put(original)
60 | }
61 |
62 | func TestElemArrGrow(t *testing.T) {
63 | var results elemArr
64 | require.Len(t, results, 0)
65 | results = results.grow(10)
66 | require.Len(t, results, 10)
67 | results = results.grow(100)
68 | require.Len(t, results, 100)
69 | }
70 |
71 | func TestElemArrGrowResetsValue(t *testing.T) {
72 | var (
73 | empty elemType
74 | results elemArr
75 | )
76 | require.Len(t, results, 0)
77 | results = results.grow(10)
78 | require.Len(t, results, 10)
79 | for _, elem := range results {
80 | require.Equal(t, empty, elem)
81 | }
82 | }
83 |
84 | func TestElemArrGrowPanic(t *testing.T) {
85 | var results elemArr
86 | require.Len(t, results, 0)
87 | results = results.grow(100)
88 | require.Len(t, results, 100)
89 | results = results[:0]
90 | results = results.grow(1)
91 | require.Len(t, results, 1)
92 | }
93 |
--------------------------------------------------------------------------------
/generics/hashmap/byteskey/map_pool_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 byteskey
22 |
23 | import (
24 | "testing"
25 | "unsafe"
26 |
27 | "github.com/m3db/m3x/pool"
28 |
29 | "github.com/golang/mock/gomock"
30 | "github.com/mauricelam/genny/generic"
31 | "github.com/stretchr/testify/require"
32 | )
33 |
34 | // nolint: structcheck
35 | func TestMapWithPooling(t *testing.T) {
36 | ctrl := gomock.NewController(t)
37 | defer ctrl.Finish()
38 |
39 | key := []byte("foo")
40 | value := generic.Type("a")
41 |
42 | pool := pool.NewMockBytesPool(ctrl)
43 |
44 | m := NewMap(MapOptions{KeyCopyPool: pool})
45 |
46 | mockPooledSlice := make([]byte, 0, 3)
47 | pool.EXPECT().Get(len(key)).Return(mockPooledSlice)
48 | m.Set(key, value)
49 | require.Equal(t, 1, m.Len())
50 |
51 | // Now ensure that the key is from the pool and not our original key
52 | for _, entry := range m.Iter() {
53 | type slice struct {
54 | array unsafe.Pointer
55 | len int
56 | cap int
57 | }
58 |
59 | keyBytes := entry.Key()
60 |
61 | rawPooledSlice := (*slice)(unsafe.Pointer(&mockPooledSlice))
62 | rawKeySlice := (*slice)(unsafe.Pointer(&keyBytes))
63 |
64 | require.True(t, rawPooledSlice.array == rawKeySlice.array)
65 | }
66 |
67 | // Now delete the key to simulate returning to pool
68 | pool.EXPECT().Put(mockPooledSlice[:3])
69 | m.Delete(key)
70 | require.Equal(t, 0, m.Len())
71 | }
72 |
--------------------------------------------------------------------------------
/generics/hashmap/byteskey/new_map.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 byteskey
22 |
23 | import (
24 | "bytes"
25 |
26 | "github.com/m3db/m3x/pool"
27 |
28 | "github.com/cespare/xxhash"
29 | "github.com/mauricelam/genny/generic"
30 | )
31 |
32 | // MapValue is the generic type that needs to be specified when generating.
33 | type MapValue generic.Type
34 |
35 | // MapOptions provides options used when created the map.
36 | type MapOptions struct {
37 | InitialSize int
38 | KeyCopyPool pool.BytesPool
39 | }
40 |
41 | // NewMap returns a new byte keyed map.
42 | func NewMap(opts MapOptions) *Map {
43 | var (
44 | copyFn CopyFn
45 | finalizeFn FinalizeFn
46 | )
47 | if pool := opts.KeyCopyPool; pool == nil {
48 | copyFn = func(k []byte) []byte {
49 | return append([]byte(nil), k...)
50 | }
51 | } else {
52 | copyFn = func(k []byte) []byte {
53 | keyLen := len(k)
54 | pooled := pool.Get(keyLen)[:keyLen]
55 | copy(pooled, k)
56 | return pooled
57 | }
58 | finalizeFn = func(k []byte) {
59 | pool.Put(k)
60 | }
61 | }
62 | return mapAlloc(mapOptions{
63 | hash: func(k []byte) MapHash {
64 | return MapHash(xxhash.Sum64(k))
65 | },
66 | equals: bytes.Equal,
67 | copy: copyFn,
68 | finalize: finalizeFn,
69 | initialSize: opts.InitialSize,
70 | })
71 | }
72 |
--------------------------------------------------------------------------------
/generics/hashmap/idkey/map_pool_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 idkey
22 |
23 | import (
24 | "testing"
25 | "unsafe"
26 |
27 | "github.com/m3db/m3x/ident"
28 | "github.com/m3db/m3x/pool"
29 |
30 | "github.com/golang/mock/gomock"
31 | "github.com/mauricelam/genny/generic"
32 | "github.com/stretchr/testify/require"
33 | )
34 |
35 | // nolint: structcheck
36 | func TestMapWithPooling(t *testing.T) {
37 | ctrl := gomock.NewController(t)
38 | defer ctrl.Finish()
39 |
40 | key := ident.StringID("foo")
41 | value := generic.Type("a")
42 |
43 | pool := pool.NewMockBytesPool(ctrl)
44 |
45 | m := NewMap(MapOptions{KeyCopyPool: pool})
46 |
47 | mockPooledSlice := make([]byte, 0, 3)
48 | pool.EXPECT().Get(len(key.Bytes())).Return(mockPooledSlice)
49 | m.Set(key, value)
50 | require.Equal(t, 1, m.Len())
51 |
52 | // Now ensure that the key is from the pool and not our original key
53 | for _, entry := range m.Iter() {
54 | type slice struct {
55 | array unsafe.Pointer
56 | len int
57 | cap int
58 | }
59 |
60 | keyBytes := []byte(entry.Key().(ident.BytesID))
61 |
62 | rawPooledSlice := (*slice)(unsafe.Pointer(&mockPooledSlice))
63 | rawKeySlice := (*slice)(unsafe.Pointer(&keyBytes))
64 |
65 | require.True(t, rawPooledSlice.array == rawKeySlice.array)
66 | }
67 |
68 | // Now delete the key to simulate returning to pool
69 | pool.EXPECT().Put(mockPooledSlice[:3])
70 | m.Delete(key)
71 | require.Equal(t, 0, m.Len())
72 | }
73 |
--------------------------------------------------------------------------------
/generics/hashmap/idkey/new_map.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 idkey
22 |
23 | import (
24 | "github.com/m3db/m3x/ident"
25 | "github.com/m3db/m3x/pool"
26 |
27 | "github.com/cespare/xxhash"
28 | "github.com/mauricelam/genny/generic"
29 | )
30 |
31 | // MapValue is the generic type that needs to be specified when generating.
32 | type MapValue generic.Type
33 |
34 | // MapOptions provides options used when created the map.
35 | type MapOptions struct {
36 | InitialSize int
37 | KeyCopyPool pool.BytesPool
38 | }
39 |
40 | // NewMap returns a new byte keyed map.
41 | func NewMap(opts MapOptions) *Map {
42 | var (
43 | copyFn CopyFn
44 | finalizeFn FinalizeFn
45 | )
46 | if pool := opts.KeyCopyPool; pool == nil {
47 | copyFn = func(k ident.ID) ident.ID {
48 | return ident.BytesID(append([]byte(nil), k.Bytes()...))
49 | }
50 | } else {
51 | copyFn = func(k ident.ID) ident.ID {
52 | bytes := k.Bytes()
53 | keyLen := len(bytes)
54 | pooled := pool.Get(keyLen)[:keyLen]
55 | copy(pooled, bytes)
56 | return ident.BytesID(pooled)
57 | }
58 | finalizeFn = func(k ident.ID) {
59 | if slice, ok := k.(ident.BytesID); ok {
60 | pool.Put(slice)
61 | }
62 | }
63 | }
64 | return mapAlloc(mapOptions{
65 | hash: func(id ident.ID) MapHash {
66 | return MapHash(xxhash.Sum64(id.Bytes()))
67 | },
68 | equals: func(x, y ident.ID) bool {
69 | return x.Equal(y)
70 | },
71 | copy: copyFn,
72 | finalize: finalizeFn,
73 | initialSize: opts.InitialSize,
74 | })
75 | }
76 |
--------------------------------------------------------------------------------
/glide.yaml:
--------------------------------------------------------------------------------
1 | package: github.com/m3db/m3x
2 | import:
3 |
4 | - package: github.com/golang/mock
5 | version: ^1.0.0
6 |
7 | - package: github.com/uber-go/tally
8 | version: ^3.3.7
9 |
10 | - package: github.com/uber-go/zap
11 | version: ^1.0.0
12 |
13 | - package: gopkg.in/validator.v2
14 | version: 3e4f037f12a1221a0864cf0dd2e81c452ab22448
15 | repo: https://github.com/go-validator/validator.git
16 |
17 | - package: gopkg.in/yaml.v2
18 | version: 5420a8b6744d3b0345ab293f6fcba19c978f1183
19 | repo: https://github.com/go-yaml/yaml.git
20 |
21 | - package: github.com/apache/thrift
22 | version: 9549b25c77587b29be4e0b5c258221a4ed85d37a
23 |
24 | - package: github.com/uber-go/atomic
25 | version: ^1.0.0
26 |
27 | - package: github.com/spaolacci/murmur3
28 | version: ^1.1.0
29 |
30 | - package: github.com/mauricelam/genny
31 | version: 9d8700bcc567cd22ea2ef42ce5835a9c80296c4a
32 |
33 | - package: github.com/cespare/xxhash
34 | version: 48099fad606eafc26e3a569fad19ff510fff4df6
35 |
36 | - package: github.com/stretchr/testify
37 | version: ^1.2.0
38 | subpackages:
39 | - assert
40 | - require
41 |
42 | - package: github.com/MichaelTJones/pcg
43 | version: df440c6ed7ed8897ac98a408365e5e89c7becf1a
44 |
45 | - package: github.com/google/go-cmp
46 | version: ^0.2
47 | subpackages:
48 | - cmp
49 |
50 | - package: github.com/uber/jaeger-lib
51 | version: ^2.0.0
52 |
53 | - package: github.com/uber/jaeger-client-go
54 | version: ^2.7.0
55 |
56 | testImport:
57 | - package: github.com/fortytw2/leaktest
58 | version: ^1.1.0
59 |
--------------------------------------------------------------------------------
/hash/doc.go:
--------------------------------------------------------------------------------
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 hash provides implementation of hash functions.
22 | package hash
23 |
--------------------------------------------------------------------------------
/hash/jump/doc.go:
--------------------------------------------------------------------------------
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 | /*
22 |
23 | Package jump implements the jump consistent hash algorithm as described in
24 | "A Fast, Minimal Memory, Consistent Hash Algorithm"[1]. As the paper notes:
25 | "In comparison to the algorithm of Karger et al., jump consistent hash
26 | requires no storage, is faster, and does a better job of evenly dividing
27 | the key space among the buckets and of evenly dividing the workload when
28 | the number of buckets changes. Its main limitation is that the buckets
29 | must be numbered sequentially, which makes it more suitable for data
30 | storage applications than for distributed web caching."
31 |
32 | [1] http://arxiv.org/pdf/1406.2294v1.pdf
33 |
34 | */
35 | package jump
36 |
--------------------------------------------------------------------------------
/hash/jump/example_test.go:
--------------------------------------------------------------------------------
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 jump_test
22 |
23 | import (
24 | "fmt"
25 | "hash/fnv"
26 | "log"
27 |
28 | "github.com/m3db/m3x/hash/jump"
29 | )
30 |
31 | func ExampleHash() {
32 | var (
33 | numBuckets int64 = 10
34 | key = []byte("foo")
35 | hasher = fnv.New64()
36 | )
37 |
38 | // Create hash of the key using whatever hash function you wish.
39 | if _, err := hasher.Write(key); err != nil {
40 | log.Fatal(err)
41 | }
42 | keyHash := hasher.Sum64()
43 |
44 | // Get which bucket the key is assigned to.
45 | bucket := jump.Hash(keyHash, numBuckets)
46 |
47 | fmt.Printf("Key '%s' is assigned to bucket %d.\n", string(key), bucket)
48 | // Output: Key 'foo' is assigned to bucket 9.
49 | }
50 |
--------------------------------------------------------------------------------
/hash/jump/jump.go:
--------------------------------------------------------------------------------
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 jump
22 |
23 | // Hash maps a uint64 to a bucket in the range [0, numBuckets).
24 | func Hash(key uint64, numBuckets int64) int64 {
25 | if numBuckets < 0 {
26 | return -1
27 | }
28 |
29 | var b, j int64
30 | for j < numBuckets {
31 | b = j
32 | key = key*2862933555777941757 + 1
33 | j = int64(float64(b+1) * (float64(int64(1)<<31) / float64((key>>33)+1)))
34 | }
35 |
36 | return b
37 | }
38 |
--------------------------------------------------------------------------------
/ident/bytes_id.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 ident
22 |
23 | import (
24 | "bytes"
25 | )
26 |
27 | // BytesID is a small utility type to avoid the heavy weight of a true ID
28 | // implementation when using in high throughput places like keys in a map.
29 | type BytesID []byte
30 |
31 | // var declaration to ensure package type BytesID implements ID
32 | var _ ID = BytesID(nil)
33 |
34 | // Bytes returns the underlying byte slice of the bytes ID.
35 | func (v BytesID) Bytes() []byte {
36 | return v
37 | }
38 |
39 | // String returns the bytes ID as a string.
40 | func (v BytesID) String() string {
41 | return string(v)
42 | }
43 |
44 | // Equal returns whether the bytes ID is equal to a given ID.
45 | func (v BytesID) Equal(value ID) bool {
46 | return bytes.Equal(value.Bytes(), v)
47 | }
48 |
49 | // NoFinalize is a no-op for a bytes ID as Finalize is already a no-op.
50 | func (v BytesID) NoFinalize() {
51 | }
52 |
53 | // IsNoFinalize is always true since BytesID is not pooled.
54 | func (v BytesID) IsNoFinalize() bool {
55 | return true
56 | }
57 |
58 | // Finalize is a no-op for a bytes ID as it has no associated pool.
59 | func (v BytesID) Finalize() {
60 | }
61 |
--------------------------------------------------------------------------------
/ident/id_matcher.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 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 ident
22 |
23 | import (
24 | "fmt"
25 |
26 | "github.com/golang/mock/gomock"
27 | )
28 |
29 | // IDMatcher is a gomock.Matcher that matches ID
30 | type IDMatcher interface {
31 | gomock.Matcher
32 | }
33 |
34 | // NewIDMatcher returns a new IDMatcher
35 | func NewIDMatcher(id string) IDMatcher {
36 | return &idMatcher{id: StringID(id)}
37 | }
38 |
39 | type idMatcher struct {
40 | id ID
41 | }
42 |
43 | func (m *idMatcher) Matches(x interface{}) bool {
44 | id, ok := x.(ID)
45 | if !ok {
46 | return false
47 | }
48 | return m.id.Equal(id)
49 | }
50 |
51 | func (m *idMatcher) String() string {
52 | return fmt.Sprintf("id %s", m.id.String())
53 | }
54 |
--------------------------------------------------------------------------------
/ident/identifier.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 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 ident
22 |
23 | import (
24 | "bytes"
25 |
26 | "github.com/m3db/m3x/checked"
27 | )
28 |
29 | // BinaryID constructs a new ID based on a binary value.
30 | func BinaryID(v checked.Bytes) ID {
31 | v.IncRef()
32 | return &id{data: v}
33 | }
34 |
35 | // StringID constructs a new ID based on a string value.
36 | func StringID(str string) ID {
37 | return BytesID([]byte(str))
38 | }
39 |
40 | type id struct {
41 | data checked.Bytes
42 | pool Pool
43 | noFinalize bool
44 | }
45 |
46 | // Bytes directly returns the underlying bytes of an ID, it is not safe
47 | // to hold a reference to this slice and is only valid during the lifetime
48 | // of the the ID itself.
49 | func (v *id) Bytes() []byte {
50 | if v.data == nil {
51 | return nil
52 | }
53 | return v.data.Bytes()
54 | }
55 |
56 | func (v *id) Equal(value ID) bool {
57 | return bytes.Equal(v.Bytes(), value.Bytes())
58 | }
59 |
60 | func (v *id) NoFinalize() {
61 | v.noFinalize = true
62 | }
63 |
64 | func (v *id) IsNoFinalize() bool {
65 | return v.noFinalize
66 | }
67 |
68 | func (v *id) Finalize() {
69 | if v.noFinalize {
70 | return
71 | }
72 | v.data.DecRef()
73 | v.data.Finalize()
74 | v.data = nil
75 |
76 | if v.pool == nil {
77 | return
78 | }
79 |
80 | v.pool.Put(v)
81 | }
82 |
83 | func (v *id) String() string {
84 | return string(v.Bytes())
85 | }
86 |
--------------------------------------------------------------------------------
/ident/identifier_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 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 ident
22 |
23 | import (
24 | "testing"
25 |
26 | "github.com/m3db/m3x/checked"
27 |
28 | "github.com/stretchr/testify/assert"
29 | "github.com/stretchr/testify/require"
30 | )
31 |
32 | func TestConstructorEquality(t *testing.T) {
33 | a := StringID("abc")
34 | b := BinaryID(checked.NewBytes([]byte{'a', 'b', 'c'}, nil))
35 |
36 | require.Equal(t, a.String(), "abc")
37 |
38 | assert.True(t, a.Equal(b))
39 | assert.Equal(t, a.String(), b.String())
40 | assert.Equal(t, a.Bytes(), b.Bytes())
41 | }
42 |
43 | func TestNoFinalize(t *testing.T) {
44 | v := StringID("abc")
45 |
46 | checkValid := func() {
47 | require.NotNil(t, v.Bytes())
48 | assert.True(t, v.Equal(StringID("abc")))
49 | }
50 | checkValid()
51 | assert.True(t, v.IsNoFinalize())
52 |
53 | v.NoFinalize()
54 | checkValid()
55 | assert.True(t, v.IsNoFinalize())
56 |
57 | for i := 0; i < 2; i++ {
58 | v.Finalize()
59 | checkValid()
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/ident/tag.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 ident
22 |
23 | import (
24 | "github.com/m3db/m3x/checked"
25 | )
26 |
27 | // BinaryTag constructs a new Tag based on binary values.
28 | func BinaryTag(name checked.Bytes, value checked.Bytes) Tag {
29 | return Tag{
30 | Name: TagName(BinaryID(name)),
31 | Value: TagValue(BinaryID(value)),
32 | }
33 | }
34 |
35 | // StringTag constructs a new Tag based on string values.
36 | func StringTag(name string, value string) Tag {
37 | return Tag{
38 | Name: TagName(StringID(name)),
39 | Value: TagValue(StringID(value)),
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/ident/tag_arraypool_gen.go:
--------------------------------------------------------------------------------
1 | // This file was automatically generated by genny.
2 | // Any changes will be lost if this file is regenerated.
3 | // see https://github.com/mauricelam/genny
4 |
5 | package ident
6 |
7 | import (
8 | "github.com/m3db/m3x/pool"
9 | )
10 |
11 | // Copyright (c) 2018 Uber Technologies, Inc.
12 | //
13 | // Permission is hereby granted, free of charge, to any person obtaining a copy
14 | // of this software and associated documentation files (the "Software"), to deal
15 | // in the Software without restriction, including without limitation the rights
16 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | // copies of the Software, and to permit persons to whom the Software is
18 | // furnished to do so, subject to the following conditions:
19 | //
20 | // The above copyright notice and this permission notice shall be included in
21 | // all copies or substantial portions of the Software.
22 | //
23 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 | // THE SOFTWARE.
30 |
31 | // tagArrayPool provides a pool for tag slices.
32 | type tagArrayPool interface {
33 | // Init initializes the array pool, it needs to be called
34 | // before Get/Put use.
35 | Init()
36 |
37 | // Get returns the a slice from the pool.
38 | Get() []Tag
39 |
40 | // Put returns the provided slice to the pool.
41 | Put(elems []Tag)
42 | }
43 |
44 | type tagFinalizeFn func([]Tag) []Tag
45 |
46 | type tagArrayPoolOpts struct {
47 | Options pool.ObjectPoolOptions
48 | Capacity int
49 | MaxCapacity int
50 | FinalizeFn tagFinalizeFn
51 | }
52 |
53 | type tagArrPool struct {
54 | opts tagArrayPoolOpts
55 | pool pool.ObjectPool
56 | }
57 |
58 | func newTagArrayPool(opts tagArrayPoolOpts) tagArrayPool {
59 | if opts.FinalizeFn == nil {
60 | opts.FinalizeFn = defaultTagFinalizerFn
61 | }
62 | p := pool.NewObjectPool(opts.Options)
63 | return &tagArrPool{opts, p}
64 | }
65 |
66 | func (p *tagArrPool) Init() {
67 | p.pool.Init(func() interface{} {
68 | return make([]Tag, 0, p.opts.Capacity)
69 | })
70 | }
71 |
72 | func (p *tagArrPool) Get() []Tag {
73 | return p.pool.Get().([]Tag)
74 | }
75 |
76 | func (p *tagArrPool) Put(arr []Tag) {
77 | arr = p.opts.FinalizeFn(arr)
78 | if max := p.opts.MaxCapacity; max > 0 && cap(arr) > max {
79 | return
80 | }
81 | p.pool.Put(arr)
82 | }
83 |
84 | func defaultTagFinalizerFn(elems []Tag) []Tag {
85 | var empty Tag
86 | for i := range elems {
87 | elems[i] = empty
88 | }
89 | elems = elems[:0]
90 | return elems
91 | }
92 |
93 | type tagArr []Tag
94 |
95 | func (elems tagArr) grow(n int) []Tag {
96 | if cap(elems) < n {
97 | elems = make([]Tag, n)
98 | }
99 | elems = elems[:n]
100 | // following compiler optimized memcpy impl
101 | // https://github.com/golang/go/wiki/CompilerOptimizations#optimized-memclr
102 | var empty Tag
103 | for i := range elems {
104 | elems[i] = empty
105 | }
106 | return elems
107 | }
108 |
--------------------------------------------------------------------------------
/ident/tag_iterator_matcher.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 ident
22 |
23 | import (
24 | "fmt"
25 |
26 | "github.com/golang/mock/gomock"
27 | )
28 |
29 | // TagIterMatcher is a gomock.Matcher that matches TagIterator
30 | type TagIterMatcher interface {
31 | gomock.Matcher
32 | }
33 |
34 | // NewTagIterMatcher returns a new TagIterMatcher
35 | func NewTagIterMatcher(iter TagIterator) TagIterMatcher {
36 | return &tagIterMatcher{iter: iter}
37 | }
38 |
39 | type tagIterMatcher struct {
40 | iter TagIterator
41 | }
42 |
43 | func (m *tagIterMatcher) Matches(x interface{}) bool {
44 | t, ok := x.(TagIterator)
45 | if !ok {
46 | return false
47 | }
48 | // duplicate to ensure the both iterators can be re-used again
49 | obs := t.Duplicate()
50 | exp := m.iter.Duplicate()
51 | for exp.Next() {
52 | if !obs.Next() {
53 | return false
54 | }
55 | obsCurrent := obs.Current()
56 | expCurrent := exp.Current()
57 | if !expCurrent.Equal(obsCurrent) {
58 | return false
59 | }
60 | }
61 | if obs.Next() {
62 | return false
63 | }
64 | if exp.Err() != obs.Err() {
65 | return false
66 | }
67 | return true
68 | }
69 |
70 | func (m *tagIterMatcher) String() string {
71 | return fmt.Sprintf("tagIter %v", m.iter)
72 | }
73 |
--------------------------------------------------------------------------------
/ident/tag_iterator_matcher_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 ident_test
22 |
23 | import (
24 | "fmt"
25 | "testing"
26 |
27 | "github.com/m3db/m3x/ident"
28 |
29 | "github.com/golang/mock/gomock"
30 | "github.com/stretchr/testify/assert"
31 | )
32 |
33 | func TestTagIteratorMatcher(t *testing.T) {
34 | iter := ident.NewTagsIterator(ident.NewTags(
35 | ident.StringTag("hello", "there"),
36 | ident.StringTag("foo", "bar")))
37 | matcher := ident.NewTagIterMatcher(iter)
38 | assert.True(t, matcher.Matches(iter))
39 | }
40 |
41 | func TestTagIteratorMatcherNotMatchingWrongType(t *testing.T) {
42 | matcher := ident.NewTagIterMatcher(ident.EmptyTagIterator)
43 | assert.False(t, matcher.Matches(1))
44 | }
45 |
46 | func TestTagIteratorMatcherNotMatchingEmpty(t *testing.T) {
47 | iter := ident.MustNewTagStringsIterator("hello", "there")
48 | matcher := ident.NewTagIterMatcher(ident.EmptyTagIterator)
49 | assert.False(t, matcher.Matches(iter))
50 | }
51 |
52 | func TestTagIteratorMatcherNotMatchingTagName(t *testing.T) {
53 | iter := ident.MustNewTagStringsIterator("hello", "there")
54 | matcher := ident.NewTagIterMatcher(iter)
55 | otherIter := ident.MustNewTagStringsIterator("hello", "other")
56 | assert.True(t, matcher.Matches(iter))
57 | assert.False(t, matcher.Matches(otherIter))
58 | }
59 |
60 | func TestTagIteratorMatcherNotMatchingTagValue(t *testing.T) {
61 | iter := ident.MustNewTagStringsIterator("hello", "there")
62 | matcher := ident.NewTagIterMatcher(iter)
63 | otherIter := ident.MustNewTagStringsIterator("fail", "there")
64 | assert.False(t, matcher.Matches(otherIter))
65 | }
66 |
67 | func TestTagIteratorMatcherErrCase(t *testing.T) {
68 | ctrl := gomock.NewController(t)
69 | defer ctrl.Finish()
70 |
71 | iter := ident.NewMockTagIterator(ctrl)
72 | gomock.InOrder(
73 | iter.EXPECT().Duplicate().Return(iter),
74 | iter.EXPECT().Next().Return(true),
75 | iter.EXPECT().Current().Return(ident.StringTag("a", "b")),
76 | iter.EXPECT().Next().Return(false),
77 | iter.EXPECT().Err().Return(fmt.Errorf("random error")),
78 | )
79 | mIter := ident.MustNewTagStringsIterator("a", "b")
80 | matcher := ident.NewTagIterMatcher(mIter)
81 | assert.False(t, matcher.Matches(iter))
82 | }
83 |
--------------------------------------------------------------------------------
/ident/tag_matcher.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 ident
22 |
23 | import (
24 | "fmt"
25 |
26 | "github.com/golang/mock/gomock"
27 | )
28 |
29 | // TagMatcher is a gomock.Matcher that matches Tag
30 | type TagMatcher interface {
31 | gomock.Matcher
32 | }
33 |
34 | // NewTagMatcher returns a new TagMatcher
35 | func NewTagMatcher(name string, value string) TagMatcher {
36 | return &tagMatcher{tag: StringTag(name, value)}
37 | }
38 |
39 | type tagMatcher struct {
40 | tag Tag
41 | }
42 |
43 | func (m *tagMatcher) Matches(x interface{}) bool {
44 | t, ok := x.(Tag)
45 | if !ok {
46 | return false
47 | }
48 | return m.tag.Name.Equal(t.Name) && m.tag.Value.Equal(t.Value)
49 | }
50 |
51 | func (m *tagMatcher) String() string {
52 | return fmt.Sprintf("tag %s=%s", m.tag.Name.String(), m.tag.Value.String())
53 | }
54 |
--------------------------------------------------------------------------------
/ident/tags_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 ident
22 |
23 | import (
24 | "testing"
25 |
26 | "github.com/stretchr/testify/require"
27 | )
28 |
29 | func TestTagsUnequalLength(t *testing.T) {
30 | tagsA := NewTags(
31 | StringTag("hello", "there"),
32 | )
33 | tagsB := NewTags(
34 | StringTag("foo", "bar"),
35 | StringTag("and", "done"),
36 | )
37 |
38 | require.False(t, tagsA.Equal(tagsB))
39 | require.False(t, tagsB.Equal(tagsA))
40 | }
41 |
42 | func TestTagsUnequalOrder(t *testing.T) {
43 | tagsA := NewTags(
44 | StringTag("foo", "bar"),
45 | StringTag("hello", "there"),
46 | )
47 | tagsB := NewTags(
48 | StringTag("hello", "there"),
49 | StringTag("foo", "bar"),
50 | )
51 |
52 | require.False(t, tagsA.Equal(tagsB))
53 | require.False(t, tagsB.Equal(tagsA))
54 | }
55 |
56 | func TestTagsEqual(t *testing.T) {
57 | tagsA := NewTags(
58 | StringTag("hello", "there"),
59 | StringTag("foo", "bar"),
60 | )
61 | tagsB := NewTags(
62 | StringTag("hello", "there"),
63 | StringTag("foo", "bar"),
64 | )
65 |
66 | require.True(t, tagsA.Equal(tagsB))
67 | require.True(t, tagsB.Equal(tagsA))
68 | }
69 |
--------------------------------------------------------------------------------
/ident/testutil/tags_convert.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 testutil
22 |
23 | import (
24 | "github.com/m3db/m3x/checked"
25 | "github.com/m3db/m3x/ident"
26 | )
27 |
28 | // NewTagsFromTagIterator allocates tags for each tag for a tag iterator, this
29 | // will copy bytes from the iterator.
30 | func NewTagsFromTagIterator(iter ident.TagIterator) (ident.Tags, error) {
31 | defer iter.Close()
32 |
33 | var r ident.Tags
34 | if tagsLen := iter.Remaining(); tagsLen > 0 {
35 | tags := make([]ident.Tag, 0, tagsLen)
36 | for iter.Next() {
37 | curr := iter.Current()
38 | tagName := checked.NewBytes(append([]byte(nil), curr.Name.Bytes()...), nil)
39 | tagValue := checked.NewBytes(append([]byte(nil), curr.Value.Bytes()...), nil)
40 | tags = append(tags, ident.BinaryTag(tagName, tagValue))
41 | }
42 | r = ident.NewTags(tags...)
43 | }
44 | if err := iter.Err(); err != nil {
45 | return ident.Tags{}, err
46 | }
47 | return r, nil
48 | }
49 |
--------------------------------------------------------------------------------
/ident/testutil/tags_convert_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 testutil
22 |
23 | import (
24 | "errors"
25 | "testing"
26 |
27 | "github.com/m3db/m3x/ident"
28 |
29 | "github.com/golang/mock/gomock"
30 | "github.com/stretchr/testify/assert"
31 | "github.com/stretchr/testify/require"
32 | )
33 |
34 | func TestNewTagsFromTagIterator(t *testing.T) {
35 | in := ident.NewTags(
36 | ident.StringTag("foo", "bar"),
37 | ident.StringTag("qux", "qaz"),
38 | )
39 | tags, err := NewTagsFromTagIterator(ident.NewTagsIterator(in))
40 | require.NoError(t, err)
41 | require.Equal(t, len(in.Values()), len(tags.Values()))
42 | for i, expected := range in.Values() {
43 | actual := tags.Values()[i]
44 | assert.True(t, expected.Equal(actual))
45 | assert.True(t, expected != actual) // Make sure made a copy
46 | }
47 | }
48 |
49 | func TestNewTagsFromTagIteratorEmptyTagIteratorDoesNotAlloc(t *testing.T) {
50 | tags, err := NewTagsFromTagIterator(ident.EmptyTagIterator)
51 | require.NoError(t, err)
52 | require.Equal(t, ident.Tags{}, tags)
53 | }
54 |
55 | func TestNewTagsFromTagIteratorError(t *testing.T) {
56 | ctrl := gomock.NewController(t)
57 | defer ctrl.Finish()
58 |
59 | expectedErr := errors.New("expected error")
60 |
61 | mockIter := ident.NewMockTagIterator(ctrl)
62 | gomock.InOrder(
63 | mockIter.EXPECT().Remaining().Return(1),
64 | mockIter.EXPECT().Next().Return(true),
65 | mockIter.EXPECT().Current().Return(ident.StringTag("foo", "bar")),
66 | mockIter.EXPECT().Next().Return(false),
67 | mockIter.EXPECT().Err().Return(expectedErr),
68 | mockIter.EXPECT().Close(),
69 | )
70 |
71 | _, err := NewTagsFromTagIterator(mockIter)
72 | require.Error(t, err)
73 | }
74 |
--------------------------------------------------------------------------------
/instrument/process.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 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 instrument
22 |
23 | import (
24 | "os"
25 | "time"
26 |
27 | "github.com/m3db/m3x/process"
28 |
29 | "github.com/uber-go/tally"
30 | )
31 |
32 | type processReporter struct {
33 | baseReporter
34 |
35 | metrics processMetrics
36 | }
37 |
38 | type processMetrics struct {
39 | NumFDs tally.Gauge
40 | NumFDErrors tally.Counter
41 | pid int
42 | }
43 |
44 | func (r *processMetrics) report() {
45 | numFDs, err := process.NumFDs(r.pid)
46 | if err == nil {
47 | r.NumFDs.Update(float64(numFDs))
48 | } else {
49 | r.NumFDErrors.Inc(1)
50 | }
51 | }
52 |
53 | // NewProcessReporter returns a new reporter that reports process
54 | // metrics, currently just the process file descriptor count.
55 | func NewProcessReporter(
56 | scope tally.Scope,
57 | reportInterval time.Duration,
58 | ) Reporter {
59 | r := new(processReporter)
60 | r.init(reportInterval, r.metrics.report)
61 |
62 | processScope := scope.SubScope("process")
63 | r.metrics.NumFDs = processScope.Gauge("num-fds")
64 | r.metrics.NumFDErrors = processScope.Counter("num-fd-errors")
65 | r.metrics.pid = os.Getpid()
66 |
67 | return r
68 | }
69 |
--------------------------------------------------------------------------------
/instrument/process_test.go:
--------------------------------------------------------------------------------
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 instrument
22 |
23 | import (
24 | "fmt"
25 | "io/ioutil"
26 | "os"
27 | "testing"
28 | "time"
29 |
30 | "github.com/fortytw2/leaktest"
31 | "github.com/stretchr/testify/assert"
32 | "github.com/stretchr/testify/require"
33 | "github.com/uber-go/tally"
34 | )
35 |
36 | func TestProcessReporter(t *testing.T) {
37 | defer leaktest.Check(t)()
38 |
39 | scope := tally.NewTestScope("", nil)
40 |
41 | countOpen := 32
42 | closeFds := func() {}
43 | for i := 0; i < countOpen; i++ {
44 | tmpFile, err := ioutil.TempFile("", "example")
45 | if err != nil {
46 | require.FailNow(t, fmt.Sprintf("could not open temp file: %v", err))
47 | }
48 |
49 | // Explicitly close with closeFds call so we can defer the leaktest
50 | // and it always executes last
51 | currCloseFds := closeFds
52 | closeFds = func() {
53 | currCloseFds()
54 | assert.NoError(t, tmpFile.Close())
55 | assert.NoError(t, os.Remove(tmpFile.Name()))
56 | }
57 | }
58 |
59 | every := 10 * time.Millisecond
60 |
61 | r := NewProcessReporter(scope, every)
62 | require.NoError(t, r.Start())
63 |
64 | time.Sleep(2 * every)
65 |
66 | _, ok := scope.Snapshot().Gauges()["process.num-fds+"]
67 | if !ok {
68 | require.FailNow(t, "metric for fds not found after waiting 2x interval")
69 | }
70 |
71 | require.NoError(t, r.Stop())
72 |
73 | closeFds()
74 | }
75 |
76 | func TestProcessReporterDoesNotOpenMoreThanOnce(t *testing.T) {
77 | r := NewProcessReporter(tally.NoopScope, 10*time.Millisecond)
78 | assert.NoError(t, r.Start())
79 | assert.Error(t, r.Start())
80 | assert.NoError(t, r.Stop())
81 | }
82 |
83 | func TestProcessReporterDoesNotCloseMoreThanOnce(t *testing.T) {
84 | r := NewProcessReporter(tally.NoopScope, 10*time.Millisecond)
85 | assert.NoError(t, r.Start())
86 | assert.NoError(t, r.Stop())
87 | assert.Error(t, r.Stop())
88 | }
89 |
90 | func TestProcessReporterDoesNotOpenWithInvalidReportInterval(t *testing.T) {
91 | r := NewProcessReporter(tally.NoopScope, 0)
92 | assert.Error(t, r.Start())
93 | }
94 |
--------------------------------------------------------------------------------
/instrument/reporter.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 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 instrument
22 |
23 | import (
24 | "errors"
25 | "sync"
26 | "time"
27 | )
28 |
29 | type reporterState int
30 |
31 | const (
32 | reporterStateNotStarted reporterState = iota
33 | reporterStateStarted
34 | reporterStateStopped
35 | )
36 |
37 | var (
38 | errReporterAlreadyStartedOrStopped = errors.New("reporter already started or stopped")
39 | errReporterNotRunning = errors.New("reporter not running")
40 | errReporterReportIntervalInvalid = errors.New("reporter report interval is invalid")
41 | )
42 |
43 | type baseReporter struct {
44 | sync.Mutex
45 |
46 | state reporterState
47 | reportInterval time.Duration
48 | closeCh chan struct{}
49 | doneCh chan struct{}
50 |
51 | // fn is the only field required to set
52 | fn func()
53 | }
54 |
55 | func (r *baseReporter) init(
56 | reportInterval time.Duration,
57 | fn func(),
58 | ) {
59 | r.reportInterval = reportInterval
60 | r.closeCh = make(chan struct{})
61 | r.doneCh = make(chan struct{})
62 | r.fn = fn
63 | }
64 |
65 | func (r *baseReporter) Start() error {
66 | r.Lock()
67 | defer r.Unlock()
68 |
69 | if r.state != reporterStateNotStarted {
70 | return errReporterAlreadyStartedOrStopped
71 | }
72 |
73 | if r.reportInterval <= 0 {
74 | return errReporterReportIntervalInvalid
75 | }
76 |
77 | r.state = reporterStateStarted
78 |
79 | go func() {
80 | ticker := time.NewTicker(r.reportInterval)
81 | defer func() {
82 | ticker.Stop()
83 | r.doneCh <- struct{}{}
84 | }()
85 |
86 | for {
87 | select {
88 | case <-ticker.C:
89 | r.fn()
90 | case <-r.closeCh:
91 | return
92 | }
93 | }
94 | }()
95 |
96 | return nil
97 | }
98 |
99 | func (r *baseReporter) Stop() error {
100 | r.Lock()
101 | defer r.Unlock()
102 |
103 | if r.state != reporterStateStarted {
104 | return errReporterNotRunning
105 | }
106 |
107 | r.state = reporterStateStopped
108 | close(r.closeCh)
109 | <-r.doneCh
110 |
111 | return nil
112 | }
113 |
--------------------------------------------------------------------------------
/instrument/types.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 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 instrument implements functions to make instrumenting code,
22 | // including metrics and logging, easier.
23 | package instrument
24 |
25 | import (
26 | "github.com/opentracing/opentracing-go"
27 | "time"
28 |
29 | "github.com/m3db/m3x/log"
30 |
31 | "github.com/uber-go/tally"
32 | "go.uber.org/zap"
33 | )
34 |
35 | // Reporter reports metrics about a component.
36 | type Reporter interface {
37 | // Start starts the reporter.
38 | Start() error
39 | // Stop stops the reporter.
40 | Stop() error
41 | }
42 |
43 | // Options represents the options for instrumentation.
44 | type Options interface {
45 | // SetLogger sets the logger.
46 | SetLogger(value log.Logger) Options
47 |
48 | // Logger returns the logger.
49 | Logger() log.Logger
50 |
51 | // SetZapLogger sets the zap logger
52 | SetZapLogger(value *zap.Logger) Options
53 |
54 | // ZapLogger returns the zap logger
55 | ZapLogger() *zap.Logger
56 |
57 | // SetMetricsScope sets the metrics scope.
58 | SetMetricsScope(value tally.Scope) Options
59 |
60 | // MetricsScope returns the metrics scope.
61 | MetricsScope() tally.Scope
62 |
63 | // Tracer returns the tracer.
64 | Tracer() opentracing.Tracer
65 |
66 | // SetTracer sets the tracer.
67 | SetTracer(tracer opentracing.Tracer) Options
68 |
69 | // SetMetricsSamplingRate sets the metrics sampling rate.
70 | SetMetricsSamplingRate(value float64) Options
71 |
72 | // SetMetricsSamplingRate returns the metrics sampling rate.
73 | MetricsSamplingRate() float64
74 |
75 | // ReportInterval sets the time between reporting metrics within the system.
76 | SetReportInterval(time.Duration) Options
77 |
78 | // GetReportInterval returns the time between reporting metrics within the system.
79 | ReportInterval() time.Duration
80 | }
81 |
--------------------------------------------------------------------------------
/log/config.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 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 log
22 |
23 | import (
24 | "io"
25 | "os"
26 | )
27 |
28 | // Configuration defines configuration for logging.
29 | type Configuration struct {
30 | File string `json:"file" yaml:"file"`
31 | Level string `json:"level" yaml:"level"`
32 | Fields map[string]interface{} `json:"fields" yaml:"fields"`
33 | }
34 |
35 | // BuildLogger builds a new Logger based on the configuration.
36 | func (cfg Configuration) BuildLogger() (Logger, error) {
37 | writer := io.Writer(os.Stdout)
38 |
39 | if cfg.File != "" {
40 | fd, err := os.OpenFile(cfg.File, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
41 | if err != nil {
42 | return nil, err
43 | }
44 |
45 | writer = io.MultiWriter(writer, fd)
46 | }
47 |
48 | logger := NewLogger(writer)
49 |
50 | if len(cfg.Level) != 0 {
51 | level, err := ParseLevel(cfg.Level)
52 | if err != nil {
53 | return nil, err
54 | }
55 |
56 | logger = NewLevelLogger(logger, level)
57 | }
58 |
59 | if len(cfg.Fields) != 0 {
60 | var fields []Field
61 | for k, v := range cfg.Fields {
62 | fields = append(fields, NewField(k, v))
63 | }
64 | logger = logger.WithFields(fields...)
65 | }
66 |
67 | return logger, nil
68 | }
69 |
--------------------------------------------------------------------------------
/log/config_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 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 log
22 |
23 | import (
24 | "io/ioutil"
25 | "os"
26 | "strings"
27 | "testing"
28 |
29 | "github.com/stretchr/testify/assert"
30 | "github.com/stretchr/testify/require"
31 | )
32 |
33 | func TestLoggingConfiguration(t *testing.T) {
34 | tmpfile, err := ioutil.TempFile("", "logtest")
35 | require.NoError(t, err)
36 |
37 | defer tmpfile.Close()
38 | defer os.Remove(tmpfile.Name())
39 |
40 | cfg := Configuration{
41 | Fields: map[string]interface{}{
42 | "my-field": "my-val",
43 | },
44 | Level: "error",
45 | File: tmpfile.Name(),
46 | }
47 |
48 | log, err := cfg.BuildLogger()
49 | require.NoError(t, err)
50 |
51 | log.Infof("should not appear")
52 | log.Warnf("should not appear")
53 | log.Errorf("this should be appear")
54 |
55 | b, err := ioutil.ReadAll(tmpfile)
56 | require.NoError(t, err)
57 |
58 | str := string(b)
59 | pieces := strings.Split(str, "[")
60 | assert.True(t, len(pieces) >= 2)
61 |
62 | ts := pieces[0]
63 | assert.EqualValues(t, ts+"[E] this should be appear [{my-field my-val}]\n", str)
64 | }
65 |
--------------------------------------------------------------------------------
/log/logger_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 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 log
22 |
23 | import (
24 | "testing"
25 |
26 | "github.com/stretchr/testify/require"
27 | )
28 |
29 | func TestNullLogger(t *testing.T) {
30 | require.NotPanics(t, func() {
31 | NullLogger.WithFields(NewField("key", "value")).Info("msg")
32 | })
33 | }
34 |
--------------------------------------------------------------------------------
/net/example_test.go:
--------------------------------------------------------------------------------
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 net_test
22 |
23 | import (
24 | "io"
25 | "log"
26 | "net"
27 |
28 | xnet "github.com/m3db/m3x/net"
29 | "github.com/m3db/m3x/retry"
30 | )
31 |
32 | func ExampleStartForeverAcceptLoop() {
33 | // Create a new listener.
34 | l, err := net.Listen("tcp", ":0")
35 | if err != nil {
36 | log.Fatal(err)
37 | }
38 | defer l.Close()
39 |
40 | // Start accepting incoming connections.
41 | var (
42 | opts = retry.NewOptions()
43 | connCh, errCh = xnet.StartAcceptLoop(l, opts)
44 | )
45 |
46 | for {
47 | select {
48 | case conn := <-connCh:
49 | // Handle the connection in a new goroutine.
50 | go func(c net.Conn) {
51 | io.Copy(c, c)
52 | c.Close()
53 | }(conn)
54 |
55 | case err := <-errCh:
56 | // Only fatal errors are returned on errCh.
57 | log.Fatal(err)
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/net/server.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 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 net implements functions for running network servers.
22 | package net
23 |
24 | import (
25 | "net"
26 |
27 | "github.com/m3db/m3x/errors"
28 | "github.com/m3db/m3x/retry"
29 | )
30 |
31 | // StartAcceptLoop starts an accept loop for the given listener,
32 | // returning accepted connections via a channel while handling
33 | // temporary network errors. Fatal errors are returned via the
34 | // error channel with the listener closed on return.
35 | func StartAcceptLoop(l net.Listener, rOpts retry.Options) (<-chan net.Conn, <-chan error) {
36 | var (
37 | connCh = make(chan net.Conn)
38 | errCh = make(chan error)
39 | retrier = retry.NewRetrier(rOpts)
40 | )
41 |
42 | go func() {
43 | defer l.Close()
44 |
45 | for {
46 | var conn net.Conn
47 | if err := retrier.Attempt(func() error {
48 | var connErr error
49 | conn, connErr = l.Accept()
50 | if connErr == nil {
51 | return nil
52 | }
53 | // If the error is a temporary network error, we consider it retryable.
54 | if ne, ok := connErr.(net.Error); ok && ne.Temporary() {
55 | return ne
56 | }
57 | // Otherwise it's a non-retryable error.
58 | return errors.NewNonRetryableError(connErr)
59 | }); err != nil {
60 | close(connCh)
61 | errCh <- err
62 | close(errCh)
63 | return
64 | }
65 | connCh <- conn
66 | }
67 | }()
68 |
69 | return connCh, errCh
70 | }
71 |
72 | // StartForeverAcceptLoop starts an accept loop for the
73 | // given listener that retries forever, returning
74 | // accepted connections via a channel while handling
75 | // temporary network errors. Fatal errors are returned via the
76 | // error channel with the listener closed on return.
77 | func StartForeverAcceptLoop(l net.Listener, rOpts retry.Options) (<-chan net.Conn, <-chan error) {
78 | return StartAcceptLoop(l, rOpts.SetForever(true))
79 | }
80 |
--------------------------------------------------------------------------------
/net/server_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 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 net
22 |
23 | import (
24 | "fmt"
25 | "io/ioutil"
26 | "net"
27 | "sort"
28 | "sync"
29 | "testing"
30 |
31 | "github.com/m3db/m3x/retry"
32 |
33 | "github.com/stretchr/testify/assert"
34 | )
35 |
36 | func TestStartAcceptLoop(t *testing.T) {
37 | var (
38 | results []string
39 | resultLock sync.Mutex
40 | wgClient sync.WaitGroup
41 | wgServer sync.WaitGroup
42 | numConnections = 10
43 | )
44 |
45 | l, err := net.Listen("tcp", "127.0.0.1:0")
46 | assert.Nil(t, err)
47 | connCh, errCh := StartForeverAcceptLoop(l, retry.NewOptions())
48 |
49 | wgServer.Add(1)
50 | go func() {
51 | defer wgServer.Done()
52 |
53 | curr := 0
54 | for conn := range connCh {
55 | fmt.Fprintf(conn, "%d", curr)
56 | conn.Close()
57 | curr++
58 | }
59 | }()
60 |
61 | for i := 0; i < numConnections; i++ {
62 | wgClient.Add(1)
63 | go func() {
64 | defer wgClient.Done()
65 |
66 | conn, err := net.Dial("tcp", l.Addr().String())
67 | assert.Nil(t, err)
68 |
69 | data, err := ioutil.ReadAll(conn)
70 | assert.Nil(t, err)
71 |
72 | resultLock.Lock()
73 | results = append(results, string(data))
74 | resultLock.Unlock()
75 | }()
76 | }
77 |
78 | wgClient.Wait()
79 |
80 | // Close the listener to intentionally cause a server-side connection error
81 | l.Close()
82 | wgServer.Wait()
83 |
84 | sort.Strings(results)
85 |
86 | var expected []string
87 | for i := 0; i < numConnections; i++ {
88 | expected = append(expected, fmt.Sprintf("%d", i))
89 | }
90 | assert.Equal(t, expected, results)
91 |
92 | // Expect a server-side connection error
93 | err = <-errCh
94 | assert.NotNil(t, err)
95 | }
96 |
--------------------------------------------------------------------------------
/opentracing/tracing.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2019 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 opentracing
22 |
23 | import (
24 | "fmt"
25 | "io"
26 |
27 | "github.com/opentracing/opentracing-go"
28 | "github.com/uber-go/tally"
29 | jaegercfg "github.com/uber/jaeger-client-go/config"
30 | jaegerzap "github.com/uber/jaeger-client-go/log/zap"
31 | jaegertally "github.com/uber/jaeger-lib/metrics/tally"
32 | "go.uber.org/zap"
33 | )
34 |
35 | // Supported tracing backends. Currently only jaeger is supported.
36 | var (
37 | TracingBackendJaeger = "jaeger"
38 | )
39 |
40 | // TracingConfiguration configures an opentracing backend for m3query to use. Currently only jaeger is supported.
41 | // Tracing is disabled if no backend is specified.
42 | type TracingConfiguration struct {
43 | Backend string `yaml:"backend"`
44 | Jaeger jaegercfg.Configuration `yaml:"jaeger"`
45 | }
46 |
47 | // NewTracer returns a tracer configured with the configuration provided by this struct. The tracer's concrete
48 | // type is determined by cfg.Backend. Currently only `"jaeger"` is supported. `""` implies
49 | // disabled (NoopTracer).
50 | func (cfg *TracingConfiguration) NewTracer(defaultServiceName string, scope tally.Scope, logger *zap.Logger) (opentracing.Tracer, io.Closer, error) {
51 | if cfg.Backend == "" {
52 | return opentracing.NoopTracer{}, noopCloser{}, nil
53 | }
54 |
55 | if cfg.Backend != TracingBackendJaeger {
56 | return nil, nil, fmt.Errorf("unknown tracing backend: %s. Supported backends are: %s", cfg.Backend, TracingBackendJaeger)
57 | }
58 |
59 | if cfg.Jaeger.ServiceName == "" {
60 | cfg.Jaeger.ServiceName = defaultServiceName
61 | }
62 |
63 | jaegerLog := jaegerzap.NewLogger(logger)
64 | tracer, jaegerCloser, err := cfg.Jaeger.NewTracer(
65 | jaegercfg.Logger(jaegerLog),
66 | jaegercfg.Metrics(jaegertally.Wrap(scope)))
67 |
68 | if err != nil {
69 | return nil, nil, fmt.Errorf("failed to initialize jaeger: %s", err.Error())
70 | }
71 |
72 | return tracer, jaegerCloser, nil
73 | }
74 |
75 | type noopCloser struct{}
76 |
77 | func (noopCloser) Close() error {
78 | return nil
79 | }
80 |
--------------------------------------------------------------------------------
/opentracing/tracing_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2019 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 opentracing
22 |
23 | import (
24 | "io"
25 | "testing"
26 |
27 | "github.com/opentracing/opentracing-go"
28 | "github.com/stretchr/testify/assert"
29 | "github.com/stretchr/testify/require"
30 | "github.com/uber-go/tally"
31 | "github.com/uber/jaeger-client-go"
32 | jaegercfg "github.com/uber/jaeger-client-go/config"
33 | "go.uber.org/zap"
34 | )
35 |
36 | func TestTracingConfiguration_NewTracer(t *testing.T) {
37 | serviceName := "foo"
38 | doCall := func(cfg *TracingConfiguration) (opentracing.Tracer, io.Closer, error) {
39 | return cfg.NewTracer(serviceName, tally.NoopScope, zap.L())
40 | }
41 |
42 | t.Run("defaults to noop", func(t *testing.T) {
43 | cfg := TracingConfiguration{}
44 | tr, closer, err := doCall(&cfg)
45 | defer closer.Close()
46 | require.NoError(t, err)
47 | assert.Equal(t, opentracing.NoopTracer{}, tr)
48 | assert.Equal(t, noopCloser{}, closer)
49 | })
50 |
51 | t.Run("errors on non-jaeger", func(t *testing.T) {
52 | cfg := TracingConfiguration{
53 | Backend: "someone_else",
54 | }
55 | _, _, err := doCall(&cfg)
56 | require.EqualError(t, err, "unknown tracing backend: someone_else. Supported backends are: jaeger")
57 | })
58 |
59 | t.Run("initializes jaeger tracer", func(t *testing.T) {
60 | cfg := TracingConfiguration{
61 | Backend: TracingBackendJaeger,
62 | }
63 | tr, closer, err := doCall(&cfg)
64 | defer closer.Close()
65 |
66 | require.NoError(t, err)
67 | assert.IsType(t, (*jaeger.Tracer)(nil), tr)
68 | })
69 |
70 | t.Run("sets service name on empty", func(t *testing.T) {
71 | cfg := TracingConfiguration{
72 | Backend: TracingBackendJaeger,
73 | }
74 | _, closer, err := doCall(&cfg)
75 | defer closer.Close()
76 |
77 | require.NoError(t, err)
78 | assert.Equal(t, serviceName, cfg.Jaeger.ServiceName)
79 | })
80 |
81 | t.Run("leaves service name on non-empty", func(t *testing.T) {
82 | cfg := TracingConfiguration{
83 | Backend: TracingBackendJaeger,
84 | Jaeger: jaegercfg.Configuration{
85 | ServiceName: "other",
86 | },
87 | }
88 | _, closer, err := doCall(&cfg)
89 | defer closer.Close()
90 |
91 | require.NoError(t, err)
92 | assert.Equal(t, "other", cfg.Jaeger.ServiceName)
93 | })
94 | }
95 |
--------------------------------------------------------------------------------
/pool/bytes.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 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 pool
22 |
23 | type bytesPool struct {
24 | pool BucketizedObjectPool
25 | }
26 |
27 | // NewBytesPool creates a new bytes pool
28 | func NewBytesPool(sizes []Bucket, opts ObjectPoolOptions) BytesPool {
29 | return &bytesPool{pool: NewBucketizedObjectPool(sizes, opts)}
30 | }
31 |
32 | func (p *bytesPool) Init() {
33 | p.pool.Init(func(capacity int) interface{} {
34 | return make([]byte, 0, capacity)
35 | })
36 | }
37 |
38 | func (p *bytesPool) Get(capacity int) []byte {
39 | if capacity < 1 {
40 | return nil
41 | }
42 |
43 | return p.pool.Get(capacity).([]byte)
44 | }
45 |
46 | func (p *bytesPool) Put(value []byte) {
47 | value = value[:0]
48 | p.pool.Put(value, cap(value))
49 | }
50 |
51 | // AppendByte appends a byte to a byte slice getting a new slice from the
52 | // BytesPool if the slice is at capacity
53 | func AppendByte(bytes []byte, b byte, pool BytesPool) []byte {
54 | if len(bytes) == cap(bytes) {
55 | newBytes := pool.Get(cap(bytes) * 2)
56 | n := copy(newBytes[:len(bytes)], bytes)
57 | pool.Put(bytes)
58 | bytes = newBytes[:n]
59 | }
60 |
61 | return append(bytes, b)
62 | }
63 |
--------------------------------------------------------------------------------
/pool/bytes_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 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 pool
22 |
23 | import (
24 | "testing"
25 |
26 | "github.com/stretchr/testify/assert"
27 | )
28 |
29 | func TestBytesPool(t *testing.T) {
30 | p := getBytesPool(2, []int{5, 10})
31 | p.Init()
32 |
33 | assert.Equal(t, []byte(nil), p.Get(0))
34 |
35 | b1 := p.Get(1)
36 | assert.Equal(t, 0, len(b1))
37 | assert.Equal(t, 5, cap(b1))
38 | b1 = append(b1, 'a')
39 |
40 | b2 := p.Get(3)
41 | assert.Equal(t, 0, len(b2))
42 | assert.Equal(t, 5, cap(b2))
43 | b2 = append(b1, 'b')
44 | assert.NotEqual(t, b1, b2)
45 | p.Put(b1)
46 |
47 | b3 := p.Get(2)
48 | assert.Equal(t, 0, len(b3))
49 | assert.Equal(t, 5, cap(b3))
50 | assert.Equal(t, b1, b3[:1])
51 | }
52 |
53 | func TestBytesPoolGetLargerThanLargestBucket(t *testing.T) {
54 | p := getBytesPool(2, []int{8})
55 | p.Init()
56 |
57 | x := p.Get(16)
58 | assert.NotNil(t, x)
59 | assert.Equal(t, 16, cap(x))
60 | assert.Equal(t, 0, len(x))
61 |
62 | // Assert not from pool
63 | bucketed := p.pool.(*bucketizedObjectPool)
64 | assert.Equal(t, 1, len(bucketed.buckets))
65 | assert.Equal(t, 2, len(bucketed.buckets[0].pool.(*objectPool).values))
66 | }
67 |
68 | func TestAppendByte(t *testing.T) {
69 | p := getBytesPool(1, []int{3, 10})
70 | p.Init()
71 | vals := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'}
72 |
73 | b1 := p.Get(2)
74 | b2 := b1
75 | for _, val := range vals {
76 | b2 = AppendByte(b2, val, p)
77 | }
78 |
79 | assert.Equal(t, b2, vals)
80 | assert.Equal(t, 9, len(b2))
81 | assert.Equal(t, 10, cap(b2))
82 |
83 | b3 := p.Get(2)
84 | assert.Equal(t, cap(b1), cap(b3))
85 | assert.Equal(t, b1[:3], b3[:3])
86 | }
87 |
88 | func getBytesPool(bucketSizes int, bucketCaps []int) *bytesPool {
89 | buckets := make([]Bucket, len(bucketCaps))
90 | for i, cap := range bucketCaps {
91 | buckets[i] = Bucket{
92 | Count: bucketSizes,
93 | Capacity: cap,
94 | }
95 | }
96 |
97 | return NewBytesPool(buckets, nil).(*bytesPool)
98 | }
99 |
--------------------------------------------------------------------------------
/pool/checked_bytes.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 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 pool
22 |
23 | import "github.com/m3db/m3x/checked"
24 |
25 | type checkedBytesPool struct {
26 | bytesPool BytesPool
27 | pool BucketizedObjectPool
28 | }
29 |
30 | // NewBytesPoolFn is a function to construct a new bytes pool
31 | type NewBytesPoolFn func(sizes []Bucket) BytesPool
32 |
33 | // NewCheckedBytesPool creates a new checked bytes pool
34 | func NewCheckedBytesPool(
35 | sizes []Bucket,
36 | opts ObjectPoolOptions,
37 | newBackingBytesPool NewBytesPoolFn,
38 | ) CheckedBytesPool {
39 | return &checkedBytesPool{
40 | bytesPool: newBackingBytesPool(sizes),
41 | pool: NewBucketizedObjectPool(sizes, opts),
42 | }
43 | }
44 |
45 | func (p *checkedBytesPool) BytesPool() BytesPool {
46 | return p.bytesPool
47 | }
48 |
49 | func (p *checkedBytesPool) Init() {
50 | opts := checked.NewBytesOptions().
51 | SetFinalizer(p)
52 |
53 | p.bytesPool.Init()
54 | p.pool.Init(func(capacity int) interface{} {
55 | value := p.bytesPool.Get(capacity)
56 | return checked.NewBytes(value, opts)
57 | })
58 | }
59 |
60 | func (p *checkedBytesPool) Get(capacity int) checked.Bytes {
61 | return p.pool.Get(capacity).(checked.Bytes)
62 | }
63 |
64 | func (p *checkedBytesPool) FinalizeBytes(bytes checked.Bytes) {
65 | bytes.IncRef()
66 | bytes.Resize(0)
67 | capacity := bytes.Cap()
68 | bytes.DecRef()
69 | p.pool.Put(bytes, capacity)
70 | }
71 |
72 | // AppendByteChecked appends a byte to a byte slice getting a new slice from
73 | // the CheckedBytesPool if the slice is at capacity
74 | func AppendByteChecked(
75 | bytes checked.Bytes,
76 | b byte,
77 | pool CheckedBytesPool,
78 | ) (
79 | result checked.Bytes,
80 | swapped bool,
81 | ) {
82 | orig := bytes
83 |
84 | if bytes.Len() == bytes.Cap() {
85 | newBytes := pool.Get(bytes.Cap() * 2)
86 |
87 | // Inc the ref to read/write to it
88 | newBytes.IncRef()
89 | newBytes.Resize(bytes.Len())
90 |
91 | copy(newBytes.Bytes(), bytes.Bytes())
92 |
93 | bytes = newBytes
94 | }
95 |
96 | bytes.Append(b)
97 |
98 | result = bytes
99 | swapped = orig != bytes
100 |
101 | if swapped {
102 | // No longer holding reference from the inc
103 | result.DecRef()
104 | }
105 |
106 | return
107 | }
108 |
--------------------------------------------------------------------------------
/pool/checked_object.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 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 pool
22 |
23 | import "github.com/m3db/m3x/checked"
24 |
25 | type checkedObjectPool struct {
26 | pool ObjectPool
27 | finalizerPool ObjectPool
28 | }
29 |
30 | type checkedObjectFinalizer struct {
31 | value checked.ReadWriteRef
32 | p *checkedObjectPool
33 | }
34 |
35 | func (f *checkedObjectFinalizer) Finalize() {
36 | f.p.pool.Put(f.value)
37 |
38 | finalizerPool := f.p.finalizerPool
39 | f.value = nil
40 | f.p = nil
41 |
42 | finalizerPool.Put(f)
43 | }
44 |
45 | // NewCheckedObjectPool creates a new checked pool
46 | func NewCheckedObjectPool(opts ObjectPoolOptions) CheckedObjectPool {
47 | if opts == nil {
48 | opts = NewObjectPoolOptions()
49 | }
50 | return &checkedObjectPool{
51 | pool: NewObjectPool(opts),
52 | finalizerPool: NewObjectPool(opts.SetInstrumentOptions(opts.InstrumentOptions().
53 | SetMetricsScope(opts.InstrumentOptions().
54 | MetricsScope().
55 | SubScope("finalizer-pool")))),
56 | }
57 | }
58 |
59 | func (p *checkedObjectPool) Init(alloc CheckedAllocator) {
60 | p.pool.Init(func() interface{} {
61 | v := alloc()
62 | v.TrackObject(v)
63 | return v
64 | })
65 | p.finalizerPool.Init(func() interface{} {
66 | return &checkedObjectFinalizer{}
67 | })
68 | }
69 |
70 | func (p *checkedObjectPool) Get() checked.ReadWriteRef {
71 | value := p.pool.Get().(checked.ReadWriteRef)
72 | finalizer := p.finalizerPool.Get().(*checkedObjectFinalizer)
73 | finalizer.value = value
74 | finalizer.p = p
75 | value.SetFinalizer(finalizer)
76 | return value
77 | }
78 |
--------------------------------------------------------------------------------
/pool/checked_object_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 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 pool
22 |
23 | import (
24 | "testing"
25 |
26 | "github.com/m3db/m3x/checked"
27 |
28 | "github.com/stretchr/testify/assert"
29 | )
30 |
31 | func TestCheckedObjectPool(t *testing.T) {
32 | type obj struct {
33 | checked.RefCount
34 | x int
35 | }
36 |
37 | opts := NewObjectPoolOptions().SetSize(1)
38 |
39 | p := NewCheckedObjectPool(opts)
40 | p.Init(func() checked.ReadWriteRef {
41 | return &obj{}
42 | })
43 |
44 | assert.Equal(t, 1, checkedObjectPoolLen(p))
45 |
46 | o := p.Get().(*obj)
47 | assert.Equal(t, 0, checkedObjectPoolLen(p))
48 |
49 | o.IncRef()
50 | o.IncWrites()
51 | o.x = 3
52 | o.DecWrites()
53 | o.DecRef()
54 | o.Finalize()
55 |
56 | assert.Equal(t, 1, checkedObjectPoolLen(p))
57 |
58 | o = p.Get().(*obj)
59 | assert.Equal(t, 0, checkedObjectPoolLen(p))
60 |
61 | o.IncRef()
62 | o.IncReads()
63 | assert.Equal(t, 3, o.x)
64 | }
65 |
66 | func TestCheckedObjectPoolNoOptions(t *testing.T) {
67 | p := NewCheckedObjectPool(nil)
68 | assert.NotNil(t, p)
69 | }
70 |
71 | func checkedObjectPoolLen(p CheckedObjectPool) int {
72 | return len(p.(*checkedObjectPool).pool.(*objectPool).values)
73 | }
74 |
--------------------------------------------------------------------------------
/pool/config_test.go:
--------------------------------------------------------------------------------
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 pool
22 |
23 | import (
24 | "testing"
25 |
26 | "github.com/m3db/m3x/instrument"
27 |
28 | "github.com/stretchr/testify/require"
29 | )
30 |
31 | func TestObjectPoolConfiguration(t *testing.T) {
32 | cfg := ObjectPoolConfiguration{
33 | Size: 1,
34 | Watermark: WatermarkConfiguration{
35 | RefillLowWatermark: 0.1,
36 | RefillHighWatermark: 0.5,
37 | },
38 | }
39 | opts := cfg.NewObjectPoolOptions(instrument.NewOptions()).(*objectPoolOptions)
40 | require.Equal(t, 1, opts.size)
41 | require.Equal(t, 0.1, opts.refillLowWatermark)
42 | require.Equal(t, 0.5, opts.refillHighWatermark)
43 | }
44 |
45 | func TestBucketizedPoolConfiguration(t *testing.T) {
46 | cfg := BucketizedPoolConfiguration{
47 | Buckets: []BucketConfiguration{
48 | {Count: 1, Capacity: 10},
49 | {Count: 2, Capacity: 20},
50 | },
51 | Watermark: WatermarkConfiguration{
52 | RefillLowWatermark: 0.1,
53 | RefillHighWatermark: 0.5,
54 | },
55 | }
56 | expectedBuckets := []Bucket{
57 | {Count: 1, Capacity: 10},
58 | {Count: 2, Capacity: 20},
59 | }
60 | require.Equal(t, expectedBuckets, cfg.NewBuckets())
61 | opts := cfg.NewObjectPoolOptions(instrument.NewOptions()).(*objectPoolOptions)
62 | require.Equal(t, 0.1, opts.refillLowWatermark)
63 | require.Equal(t, 0.5, opts.refillHighWatermark)
64 | }
65 |
--------------------------------------------------------------------------------
/pool/example_test.go:
--------------------------------------------------------------------------------
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 pool_test
22 |
23 | import (
24 | "fmt"
25 |
26 | "github.com/m3db/m3x/pool"
27 | )
28 |
29 | type exampleObject struct {
30 | a, b, c int64
31 | }
32 |
33 | func (o *exampleObject) reset() {
34 | o.a = 0
35 | o.b = 0
36 | o.c = 0
37 | }
38 |
39 | func ExampleObjectPool() {
40 | opts := pool.NewObjectPoolOptions()
41 | p := pool.NewObjectPool(opts)
42 | p.Init(func() interface{} {
43 | // The Pool's Allocator should generally only return pointer
44 | // types, since a pointer can be put into the return interface
45 | // value without an allocation.
46 | return new(exampleObject)
47 | })
48 |
49 | // Get an exampleObject from the pool.
50 | o := p.Get().(*exampleObject)
51 |
52 | fmt.Printf("Retrieved struct should have default values: %+v", o)
53 | // Output: Retrieved struct should have default values: &{a:0 b:0 c:0}
54 |
55 | // Use the exampleObject.
56 | _ = o
57 |
58 | // Reset the exampleObject and return it to the pool.
59 | o.reset()
60 | p.Put(o)
61 | }
62 |
--------------------------------------------------------------------------------
/pool/floats.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 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 pool
22 |
23 | type floatsPool struct {
24 | pool BucketizedObjectPool
25 | }
26 |
27 | // NewFloatsPool creates a new floats pool
28 | func NewFloatsPool(sizes []Bucket, opts ObjectPoolOptions) FloatsPool {
29 | return &floatsPool{pool: NewBucketizedObjectPool(sizes, opts)}
30 | }
31 |
32 | func (p *floatsPool) Init() {
33 | p.pool.Init(func(capacity int) interface{} {
34 | return make([]float64, 0, capacity)
35 | })
36 | }
37 |
38 | func (p *floatsPool) Get(capacity int) []float64 {
39 | return p.pool.Get(capacity).([]float64)
40 | }
41 |
42 | func (p *floatsPool) Put(value []float64) {
43 | value = value[:0]
44 | p.pool.Put(value, cap(value))
45 | }
46 |
--------------------------------------------------------------------------------
/pool/floats_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 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 pool
22 |
23 | import (
24 | "testing"
25 |
26 | "github.com/stretchr/testify/assert"
27 | )
28 |
29 | func TestFloatsPool(t *testing.T) {
30 | p := getFloatsPool(2, []int{5, 10})
31 | p.Init()
32 |
33 | f1 := p.Get(1)
34 | assert.Equal(t, 0, len(f1))
35 | assert.Equal(t, 5, cap(f1))
36 | f1 = append(f1, 1.0)
37 |
38 | f2 := p.Get(3)
39 | assert.Equal(t, 0, len(f2))
40 | assert.Equal(t, 5, cap(f2))
41 | f2 = append(f1, 2.0)
42 | assert.NotEqual(t, f1, f2)
43 | p.Put(f1)
44 |
45 | f3 := p.Get(2)
46 | assert.Equal(t, 0, len(f3))
47 | assert.Equal(t, 5, cap(f3))
48 | assert.Equal(t, f1, f3[:1])
49 | }
50 |
51 | // nolint: unparam
52 | func getFloatsPool(bucketSizes int, bucketCaps []int) *floatsPool {
53 | buckets := make([]Bucket, len(bucketCaps))
54 | for i, cap := range bucketCaps {
55 | buckets[i] = Bucket{
56 | Count: bucketSizes,
57 | Capacity: cap,
58 | }
59 | }
60 |
61 | return NewFloatsPool(buckets, nil).(*floatsPool)
62 | }
63 |
--------------------------------------------------------------------------------
/pool/options.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 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 pool
22 |
23 | import "github.com/m3db/m3x/instrument"
24 |
25 | const (
26 | defaultSize = 4096
27 | defaultRefillLowWatermark = 0.0
28 | defaultRefillHighWatermark = 0.0
29 | )
30 |
31 | type objectPoolOptions struct {
32 | size int
33 | refillLowWatermark float64
34 | refillHighWatermark float64
35 | instrumentOpts instrument.Options
36 | onPoolAccessErrorFn OnPoolAccessErrorFn
37 | }
38 |
39 | // NewObjectPoolOptions creates a new set of object pool options
40 | func NewObjectPoolOptions() ObjectPoolOptions {
41 | return &objectPoolOptions{
42 | size: defaultSize,
43 | refillLowWatermark: defaultRefillLowWatermark,
44 | refillHighWatermark: defaultRefillHighWatermark,
45 | instrumentOpts: instrument.NewOptions(),
46 | onPoolAccessErrorFn: func(err error) { panic(err) },
47 | }
48 | }
49 |
50 | func (o *objectPoolOptions) SetSize(value int) ObjectPoolOptions {
51 | opts := *o
52 | opts.size = value
53 | return &opts
54 | }
55 |
56 | func (o *objectPoolOptions) Size() int {
57 | return o.size
58 | }
59 |
60 | func (o *objectPoolOptions) SetRefillLowWatermark(value float64) ObjectPoolOptions {
61 | opts := *o
62 | opts.refillLowWatermark = value
63 | return &opts
64 | }
65 |
66 | func (o *objectPoolOptions) RefillLowWatermark() float64 {
67 | return o.refillLowWatermark
68 | }
69 |
70 | func (o *objectPoolOptions) SetRefillHighWatermark(value float64) ObjectPoolOptions {
71 | opts := *o
72 | opts.refillHighWatermark = value
73 | return &opts
74 | }
75 |
76 | func (o *objectPoolOptions) RefillHighWatermark() float64 {
77 | return o.refillHighWatermark
78 | }
79 |
80 | func (o *objectPoolOptions) SetInstrumentOptions(value instrument.Options) ObjectPoolOptions {
81 | opts := *o
82 | opts.instrumentOpts = value
83 | return &opts
84 | }
85 |
86 | func (o *objectPoolOptions) InstrumentOptions() instrument.Options {
87 | return o.instrumentOpts
88 | }
89 |
90 | func (o *objectPoolOptions) SetOnPoolAccessErrorFn(value OnPoolAccessErrorFn) ObjectPoolOptions {
91 | opts := *o
92 | opts.onPoolAccessErrorFn = value
93 | return &opts
94 | }
95 |
96 | func (o *objectPoolOptions) OnPoolAccessErrorFn() OnPoolAccessErrorFn {
97 | return o.onPoolAccessErrorFn
98 | }
99 |
--------------------------------------------------------------------------------
/pprof/pprof.go:
--------------------------------------------------------------------------------
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 pprof provides a function for registering a HTTP handler for pprof
22 | // endpoints.
23 | package pprof
24 |
25 | import (
26 | "net/http"
27 | "net/http/pprof"
28 | "strings"
29 | )
30 |
31 | const (
32 | pprofPath = "/debug/pprof/"
33 | )
34 |
35 | // RegisterHandler registers the pprof handler with the given http mux.
36 | func RegisterHandler(mux *http.ServeMux) {
37 | mux.Handle(pprofPath, handler())
38 | }
39 |
40 | func handler() http.Handler {
41 | h := func(w http.ResponseWriter, r *http.Request) {
42 | name := strings.TrimPrefix(r.URL.Path, pprofPath)
43 | switch name {
44 | case "cmdline":
45 | pprof.Cmdline(w, r)
46 | case "profile":
47 | pprof.Profile(w, r)
48 | case "symbol":
49 | pprof.Symbol(w, r)
50 | case "trace":
51 | pprof.Trace(w, r)
52 | default:
53 | pprof.Index(w, r)
54 | }
55 | }
56 | return http.HandlerFunc(h)
57 | }
58 |
--------------------------------------------------------------------------------
/pprof/pprof_test.go:
--------------------------------------------------------------------------------
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 pprof
22 |
23 | import (
24 | "net/http"
25 | "net/http/httptest"
26 | "testing"
27 |
28 | "github.com/stretchr/testify/require"
29 | )
30 |
31 | func TestHandler(t *testing.T) {
32 | s := httptest.NewServer(handler())
33 | url := s.URL + pprofPath
34 | defer s.Close()
35 |
36 | for _, endpoint := range []string{
37 | "",
38 | "cmdline",
39 | "symbol",
40 | "profile?seconds=1",
41 | "trace?seconds=1",
42 | "goroutine?debug=2",
43 | } {
44 | resp, err := http.Get(url + endpoint)
45 | require.NoError(t, err)
46 | require.Equal(t, http.StatusOK, resp.StatusCode)
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/process/process_linux.go:
--------------------------------------------------------------------------------
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 process provides functions for inspecting processes.
22 | package process
23 |
24 | import (
25 | "fmt"
26 | "os"
27 | )
28 |
29 | // NumFDs returns the number of file descriptors for a given process.
30 | // This is more efficient than the NumFDs() method in the psutils package
31 | // by avoiding reading the destination of the symlinks in the proc directory.
32 | func NumFDs(pid int) (int, error) {
33 | statPath := fmt.Sprintf("/proc/%d/fd", pid)
34 | d, err := os.Open(statPath)
35 | if err != nil {
36 | return 0, err
37 | }
38 | fnames, err := d.Readdirnames(-1)
39 | d.Close()
40 | return len(fnames), err
41 | }
42 |
--------------------------------------------------------------------------------
/process/process_notlinux.go:
--------------------------------------------------------------------------------
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 | // +build !linux
22 |
23 | package process
24 |
25 | import (
26 | "errors"
27 | )
28 |
29 | var errNotAvailable = errors.New(
30 | "cannot get process file descriptors, only available on linux")
31 |
32 | // NumFDs returns the number of file descriptors for a given process.
33 | func NumFDs(pid int) (int, error) {
34 | return 0, errNotAvailable
35 | }
36 |
--------------------------------------------------------------------------------
/resource/types.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 resource describes require for object lifecycle management.
22 | // Both Finalizer and Closer have similar concepts, they both exist so that
23 | // different types can be used for resource cleanup with different method names
24 | // as for some things like iterators, the verb close makes more sense than
25 | // finalize and is more consistent with other types.
26 | package resource
27 |
28 | // Finalizer finalizes a checked resource.
29 | type Finalizer interface {
30 | Finalize()
31 | }
32 |
33 | // FinalizerFn is a function literal that is a finalizer.
34 | type FinalizerFn func()
35 |
36 | // Finalize will call the function literal as a finalizer.
37 | func (fn FinalizerFn) Finalize() {
38 | fn()
39 | }
40 |
41 | // Closer is an object that can be closed.
42 | type Closer interface {
43 | Close()
44 | }
45 |
46 | // CloserFn is a function literal that is a closer.
47 | type CloserFn func()
48 |
49 | // Close will call the function literal as a closer.
50 | func (fn CloserFn) Close() {
51 | fn()
52 | }
53 |
--------------------------------------------------------------------------------
/retry/config.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 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 retry
22 |
23 | import (
24 | "time"
25 |
26 | "github.com/uber-go/tally"
27 | )
28 |
29 | // Configuration configures options for retry attempts.
30 | type Configuration struct {
31 | // Initial retry backoff.
32 | InitialBackoff time.Duration `yaml:"initialBackoff" validate:"min=0"`
33 |
34 | // Backoff factor for exponential backoff.
35 | BackoffFactor float64 `yaml:"backoffFactor" validate:"min=0"`
36 |
37 | // Maximum backoff time.
38 | MaxBackoff time.Duration `yaml:"maxBackoff" validate:"min=0"`
39 |
40 | // Maximum number of retry attempts.
41 | MaxRetries int `yaml:"maxRetries"`
42 |
43 | // Whether to retry forever until either the attempt succeeds,
44 | // or the retry condition becomes false.
45 | Forever *bool `yaml:"forever"`
46 |
47 | // Whether jittering is applied during retries.
48 | Jitter *bool `yaml:"jitter"`
49 | }
50 |
51 | // NewOptions creates a new retry options based on the configuration.
52 | func (c Configuration) NewOptions(scope tally.Scope) Options {
53 | opts := NewOptions().SetMetricsScope(scope)
54 | if c.InitialBackoff != 0 {
55 | opts = opts.SetInitialBackoff(c.InitialBackoff)
56 | }
57 | if c.BackoffFactor != 0.0 {
58 | opts = opts.SetBackoffFactor(c.BackoffFactor)
59 | }
60 | if c.MaxBackoff != 0 {
61 | opts = opts.SetMaxBackoff(c.MaxBackoff)
62 | }
63 | if c.MaxRetries != 0 {
64 | opts = opts.SetMaxRetries(c.MaxRetries)
65 | }
66 | if c.Forever != nil {
67 | opts = opts.SetForever(*c.Forever)
68 | }
69 | if c.Jitter != nil {
70 | opts = opts.SetJitter(*c.Jitter)
71 | }
72 |
73 | return opts
74 | }
75 |
76 | // NewRetrier creates a new retrier based on the configuration.
77 | func (c Configuration) NewRetrier(scope tally.Scope) Retrier {
78 | return NewRetrier(c.NewOptions(scope))
79 | }
80 |
--------------------------------------------------------------------------------
/retry/config_test.go:
--------------------------------------------------------------------------------
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 retry
22 |
23 | import (
24 | "testing"
25 | "time"
26 |
27 | "github.com/stretchr/testify/require"
28 | "github.com/uber-go/tally"
29 | )
30 |
31 | func TestRetryConfig(t *testing.T) {
32 | b1 := true
33 | b2 := false
34 | cfg := Configuration{
35 | InitialBackoff: time.Second,
36 | BackoffFactor: 2.0,
37 | MaxBackoff: time.Minute,
38 | MaxRetries: 3,
39 | Forever: &b1,
40 | Jitter: &b2,
41 | }
42 | retrier := cfg.NewRetrier(tally.NoopScope).(*retrier)
43 | require.Equal(t, time.Second, retrier.initialBackoff)
44 | require.Equal(t, 2.0, retrier.backoffFactor)
45 | require.Equal(t, time.Minute, retrier.maxBackoff)
46 | require.Equal(t, 3, retrier.maxRetries)
47 | require.Equal(t, b1, retrier.forever)
48 | require.Equal(t, b2, retrier.jitter)
49 | }
50 |
--------------------------------------------------------------------------------
/retry/example_test.go:
--------------------------------------------------------------------------------
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 retry_test
22 |
23 | import (
24 | "context"
25 | "errors"
26 | "fmt"
27 | "log"
28 |
29 | "github.com/m3db/m3x/retry"
30 | )
31 |
32 | func ExampleRetrier() {
33 | var (
34 | opts = retry.NewOptions()
35 | retrier = retry.NewRetrier(opts)
36 | context = context.Background()
37 | )
38 |
39 | continueFn := func(attempt int) bool {
40 | // Check if the context has been canceled.
41 | select {
42 | case <-context.Done():
43 | return false
44 | default:
45 | return true
46 | }
47 | }
48 |
49 | var attempts int
50 | fn := func() error {
51 | // Perform some work which may fail.
52 |
53 | if attempts++; attempts == 3 {
54 | fmt.Printf("Attempt %v succeeded", attempts)
55 | // Output: Attempt 3 succeeded
56 |
57 | return nil
58 | }
59 | return errors.New("test")
60 | }
61 |
62 | if err := retrier.AttemptWhile(continueFn, fn); err != nil {
63 | log.Fatal(err)
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/sampler/sampler.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 sampler
22 |
23 | import (
24 | "fmt"
25 |
26 | "go.uber.org/atomic"
27 | )
28 |
29 | // Sampler samples the requests, out of 100 sample calls,
30 | // 100*sampleRate calls will be sampled.
31 | type Sampler struct {
32 | sampleEvery int32
33 | numTried *atomic.Int32
34 | }
35 |
36 | // NewSampler creates a new sampler with a sample rate.
37 | func NewSampler(sampleRate float64) (*Sampler, error) {
38 | if sampleRate <= 0.0 || sampleRate >= 1.0 {
39 | return nil, fmt.Errorf("invalid sample rate %f", sampleRate)
40 | }
41 | return &Sampler{numTried: atomic.NewInt32(0), sampleEvery: int32(1.0 / sampleRate)}, nil
42 | }
43 |
44 | // Sample returns true when the call is sampled.
45 | func (t *Sampler) Sample() bool {
46 | return (t.numTried.Inc()-1)%t.sampleEvery == 0
47 | }
48 |
--------------------------------------------------------------------------------
/sampler/sampler_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 sampler
22 |
23 | import (
24 | "testing"
25 |
26 | "github.com/stretchr/testify/require"
27 | )
28 |
29 | func TestInvalidSampleRate(t *testing.T) {
30 | _, err := NewSampler(-1.0)
31 | require.Error(t, err)
32 |
33 | _, err = NewSampler(0.0)
34 | require.Error(t, err)
35 |
36 | _, err = NewSampler(1.0)
37 | require.Error(t, err)
38 |
39 | _, err = NewSampler(2.0)
40 | require.Error(t, err)
41 | }
42 |
43 | func TestSampler(t *testing.T) {
44 | s, err := NewSampler(0.5)
45 | require.NoError(t, err)
46 | require.True(t, s.Sample())
47 | require.False(t, s.Sample())
48 | require.True(t, s.Sample())
49 | require.False(t, s.Sample())
50 | require.True(t, s.Sample())
51 |
52 | s, err = NewSampler(0.25)
53 | require.NoError(t, err)
54 | require.True(t, s.Sample())
55 | require.False(t, s.Sample())
56 | require.False(t, s.Sample())
57 | require.False(t, s.Sample())
58 | require.True(t, s.Sample())
59 | require.False(t, s.Sample())
60 | require.False(t, s.Sample())
61 | require.False(t, s.Sample())
62 | require.True(t, s.Sample())
63 | }
64 |
--------------------------------------------------------------------------------
/server/config.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 server
22 |
23 | import (
24 | "time"
25 |
26 | "github.com/m3db/m3x/instrument"
27 | "github.com/m3db/m3x/retry"
28 | )
29 |
30 | // Configuration configs a server.
31 | type Configuration struct {
32 | // Server listening address.
33 | ListenAddress string `yaml:"listenAddress" validate:"nonzero"`
34 |
35 | // Retry mechanism configuration.
36 | Retry retry.Configuration `yaml:"retry"`
37 |
38 | // Whether keep alives are enabled on connections.
39 | KeepAliveEnabled *bool `yaml:"keepAliveEnabled"`
40 |
41 | // KeepAlive period.
42 | KeepAlivePeriod *time.Duration `yaml:"keepAlivePeriod"`
43 | }
44 |
45 | // NewOptions creates server options.
46 | func (c Configuration) NewOptions(iOpts instrument.Options) Options {
47 | opts := NewOptions().
48 | SetRetryOptions(c.Retry.NewOptions(iOpts.MetricsScope())).
49 | SetInstrumentOptions(iOpts)
50 | if c.KeepAliveEnabled != nil {
51 | opts = opts.SetTCPConnectionKeepAlive(*c.KeepAliveEnabled)
52 | }
53 | if c.KeepAlivePeriod != nil {
54 | opts = opts.SetTCPConnectionKeepAlivePeriod(*c.KeepAlivePeriod)
55 | }
56 | return opts
57 | }
58 |
59 | // NewServer creates a new server.
60 | func (c Configuration) NewServer(handler Handler, iOpts instrument.Options) Server {
61 | return NewServer(c.ListenAddress, handler, c.NewOptions(iOpts))
62 | }
63 |
--------------------------------------------------------------------------------
/server/config_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 server
22 |
23 | import (
24 | "testing"
25 | "time"
26 |
27 | "github.com/m3db/m3x/instrument"
28 |
29 | "github.com/stretchr/testify/require"
30 | yaml "gopkg.in/yaml.v2"
31 | )
32 |
33 | func TestServerConfiguration(t *testing.T) {
34 | str := `
35 | listenAddress: addr
36 | keepAliveEnabled: true
37 | keepAlivePeriod: 5s
38 | `
39 |
40 | var cfg Configuration
41 | require.NoError(t, yaml.Unmarshal([]byte(str), &cfg))
42 | require.Equal(t, "addr", cfg.ListenAddress)
43 | require.True(t, *cfg.KeepAliveEnabled)
44 | require.Equal(t, 5*time.Second, *cfg.KeepAlivePeriod)
45 |
46 | opts := cfg.NewOptions(instrument.NewOptions())
47 | require.Equal(t, 5*time.Second, opts.TCPConnectionKeepAlivePeriod())
48 | require.True(t, opts.TCPConnectionKeepAlive())
49 |
50 | require.NotNil(t, cfg.NewServer(nil, instrument.NewOptions()))
51 | }
52 |
--------------------------------------------------------------------------------
/server/example_test.go:
--------------------------------------------------------------------------------
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 server_test
22 |
23 | import (
24 | "log"
25 | "net"
26 |
27 | xserver "github.com/m3db/m3x/server"
28 | )
29 |
30 | type simpleHandler struct{}
31 |
32 | func (h *simpleHandler) Handle(conn net.Conn) { conn.Close() }
33 | func (h *simpleHandler) Close() {}
34 |
35 | func ExampleServer() {
36 | var (
37 | address = ":0"
38 | handler = &simpleHandler{}
39 | opts = xserver.NewOptions()
40 | )
41 |
42 | s := xserver.NewServer(address, handler, opts)
43 |
44 | if err := s.ListenAndServe(); err != nil {
45 | log.Fatal(err)
46 | }
47 |
48 | // Block indefintely so server can run.
49 | select {}
50 | }
51 |
--------------------------------------------------------------------------------
/sync/example_test.go:
--------------------------------------------------------------------------------
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 sync_test
22 |
23 | import (
24 | "fmt"
25 | "log"
26 | "sync"
27 |
28 | xsync "github.com/m3db/m3x/sync"
29 | )
30 |
31 | type response struct {
32 | a int
33 | }
34 |
35 | func ExampleWorkerPool() {
36 | var (
37 | wg sync.WaitGroup
38 | workers = xsync.NewWorkerPool(3)
39 | errorCh = make(chan error, 1)
40 | numRequests = 9
41 | responses = make([]response, numRequests)
42 | )
43 |
44 | wg.Add(numRequests)
45 | workers.Init()
46 |
47 | for i := 0; i < numRequests; i++ {
48 | // Capture loop variable.
49 | i := i
50 |
51 | // Execute request on worker pool.
52 | workers.Go(func() {
53 | defer wg.Done()
54 |
55 | var err error
56 |
57 | // Perform some work which may fail.
58 | resp := response{a: i}
59 |
60 | if err != nil {
61 | // Return the first error that is encountered.
62 | select {
63 | case errorCh <- err:
64 | default:
65 | }
66 |
67 | return
68 | }
69 |
70 | // Can concurrently modify responses since each iteration updates a
71 | // different index.
72 | responses[i] = resp
73 | })
74 | }
75 |
76 | // Wait for all requests to finish.
77 | wg.Wait()
78 |
79 | close(errorCh)
80 | if err := <-errorCh; err != nil {
81 | log.Fatal(err)
82 | }
83 |
84 | var total int
85 | for _, r := range responses {
86 | total += r.a
87 | }
88 |
89 | fmt.Printf("Total is %v", total)
90 | // Output: Total is 36
91 | }
92 |
--------------------------------------------------------------------------------
/sync/worker_pool.go:
--------------------------------------------------------------------------------
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 sync implements synchronization facililites such as worker pools.
22 | package sync
23 |
24 | import (
25 | "time"
26 | )
27 |
28 | type workerPool struct {
29 | workCh chan struct{}
30 | }
31 |
32 | // NewWorkerPool creates a new worker pool.
33 | func NewWorkerPool(size int) WorkerPool {
34 | return &workerPool{workCh: make(chan struct{}, size)}
35 | }
36 |
37 | func (p *workerPool) Init() {
38 | for i := 0; i < cap(p.workCh); i++ {
39 | p.workCh <- struct{}{}
40 | }
41 | }
42 |
43 | func (p *workerPool) Go(work Work) {
44 | token := <-p.workCh
45 | go func() {
46 | work()
47 | p.workCh <- token
48 | }()
49 | }
50 |
51 | func (p *workerPool) GoIfAvailable(work Work) bool {
52 | select {
53 | case token := <-p.workCh:
54 | go func() {
55 | work()
56 | p.workCh <- token
57 | }()
58 | return true
59 | default:
60 | return false
61 | }
62 | }
63 |
64 | func (p *workerPool) GoWithTimeout(work Work, timeout time.Duration) bool {
65 | select {
66 | case token := <-p.workCh:
67 | go func() {
68 | work()
69 | p.workCh <- token
70 | }()
71 | return true
72 | case <-time.After(timeout):
73 | return false
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/tcp/tcp.go:
--------------------------------------------------------------------------------
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 tcp implements a tcp listener.
22 | package tcp
23 |
24 | import (
25 | "net"
26 | "time"
27 | )
28 |
29 | // NewTCPListener is Listener specifically for TCP
30 | //
31 | // TODO(jeromefroe): Move this into the net package which covers network I/O.
32 | func NewTCPListener(listenAddress string, keepAlivePeriod time.Duration) (net.Listener, error) {
33 | l, err := net.Listen("tcp", listenAddress)
34 | if err != nil {
35 | return nil, err
36 | }
37 | return tcpKeepAliveListener{l.(*net.TCPListener), keepAlivePeriod}, err
38 | }
39 |
40 | // tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
41 | // connections. It's used by ListenAndServe and ListenAndServeTLS so
42 | // dead TCP connections (e.g. closing laptop mid-download) eventually
43 | // go away. This is cargo culted from http/server.go
44 | type tcpKeepAliveListener struct {
45 | *net.TCPListener
46 | keepAlivePeriod time.Duration
47 | }
48 |
49 | func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
50 | tc, err := ln.AcceptTCP()
51 | if err != nil {
52 | return
53 | }
54 | tc.SetKeepAlive(true)
55 | tc.SetKeepAlivePeriod(ln.keepAlivePeriod)
56 | return tc, nil
57 | }
58 |
--------------------------------------------------------------------------------
/test/matcher.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 test
22 |
23 | import (
24 | "fmt"
25 |
26 | "github.com/golang/mock/gomock"
27 | "github.com/google/go-cmp/cmp"
28 | )
29 |
30 | // CmpMatcher returns a new matcher backed by go-cmp/cmp.Equal.
31 | func CmpMatcher(x interface{}, opts ...cmp.Option) gomock.Matcher {
32 | return &matcher{x, opts}
33 | }
34 |
35 | type matcher struct {
36 | expected interface{}
37 | opts cmp.Options
38 | }
39 |
40 | func (m matcher) Matches(x interface{}) bool {
41 | return cmp.Equal(m.expected, x, m.opts...)
42 | }
43 |
44 | func (m matcher) String() string {
45 | return fmt.Sprintf("%v", m.expected)
46 | }
47 |
--------------------------------------------------------------------------------
/test/reporter.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018 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 test contains utility methods for testing.
22 | package test
23 |
24 | import (
25 | "fmt"
26 | "testing"
27 |
28 | "github.com/golang/mock/gomock"
29 | )
30 |
31 | // Reporter wraps a *testing.T, and provides a more useful failure mode
32 | // when interacting with gomock.Controller.
33 | //
34 | // For example, consider:
35 | // func TestMyThing(t *testing.T) {
36 | // mockCtrl := gomock.NewController(t)
37 | // defer mockCtrl.Finish()
38 | // mockObj := something.NewMockMyInterface(mockCtrl)
39 | // go func() {
40 | // mockObj.SomeMethod(4, "blah")
41 | // }
42 | // }
43 | //
44 | // It hangs without any indication that it's missing an EXPECT() on `mockObj`.
45 | // Providing the Reporter to the gomock.Controller ctor avoids this, and terminates
46 | // with useful feedback. i.e.
47 | // func TestMyThing(t *testing.T) {
48 | // mockCtrl := gomock.NewController(test.Reporter{t})
49 | // defer mockCtrl.Finish()
50 | // mockObj := something.NewMockMyInterface(mockCtrl)
51 | // go func() {
52 | // mockObj.SomeMethod(4, "blah") // crashes the test now
53 | // }
54 | // }
55 | type Reporter struct {
56 | T *testing.T
57 | }
58 |
59 | // ensure Reporter implements gomock.TestReporter.
60 | var _ gomock.TestReporter = Reporter{}
61 |
62 | // Errorf is equivalent testing.T.Errorf.
63 | func (r Reporter) Errorf(format string, args ...interface{}) {
64 | r.T.Errorf(format, args...)
65 | }
66 |
67 | // Fatalf crashes the program with a panic to allow users to diagnose
68 | // missing expects.
69 | func (r Reporter) Fatalf(format string, args ...interface{}) {
70 | panic(fmt.Sprintf(format, args...))
71 | }
72 |
--------------------------------------------------------------------------------
/time/matcher.go:
--------------------------------------------------------------------------------
1 | package time
2 |
3 | import (
4 | "fmt"
5 | "time"
6 |
7 | "github.com/golang/mock/gomock"
8 | )
9 |
10 | // Matcher is a gomock.Matcher that matches time.Time
11 | type Matcher interface {
12 | gomock.Matcher
13 | }
14 |
15 | // NewMatcher returns a new Matcher
16 | func NewMatcher(t time.Time) Matcher {
17 | return &matcher{t: t}
18 | }
19 |
20 | type matcher struct {
21 | t time.Time
22 | }
23 |
24 | func (m *matcher) Matches(x interface{}) bool {
25 | timeStruct, ok := x.(time.Time)
26 | if !ok {
27 | return false
28 | }
29 | return m.t.Equal(timeStruct)
30 | }
31 |
32 | func (m *matcher) String() string {
33 | return fmt.Sprintf("time: %s", m.t.String())
34 | }
35 |
--------------------------------------------------------------------------------
/time/matcher_test.go:
--------------------------------------------------------------------------------
1 | package time
2 |
3 | import (
4 | "testing"
5 | "time"
6 |
7 | "github.com/stretchr/testify/require"
8 | )
9 |
10 | func TestMatcher(t *testing.T) {
11 | loc, _ := time.LoadLocation("Asia/Shanghai")
12 | t1 := time.Now().UTC()
13 | t2 := t1.In(loc)
14 |
15 | // Make sure t1 and t2 don't == eachother
16 | require.NotEqual(t, t1, t2)
17 |
18 | // Make sure t1 and t2 Match eachother
19 | t1Matcher := NewMatcher(t1)
20 | require.True(t, t1Matcher.Matches(t2))
21 |
22 | // Make sure the matcher doesn't always return true
23 | require.NotEqual(t, t1Matcher, t2.Add(1*time.Hour))
24 | require.NotEqual(t, t1Matcher, 10)
25 | }
26 |
--------------------------------------------------------------------------------
/time/range_iter.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 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 time
22 |
23 | import "container/list"
24 |
25 | // RangeIter iterates over a collection of time ranges.
26 | type RangeIter struct {
27 | ranges *list.List
28 | cur *list.Element
29 | }
30 |
31 | func newRangeIter(ranges *list.List) *RangeIter {
32 | return &RangeIter{ranges: ranges}
33 | }
34 |
35 | // Next moves to the next item.
36 | func (it *RangeIter) Next() bool {
37 | if it.ranges == nil {
38 | return false
39 | }
40 | if it.cur == nil {
41 | it.cur = it.ranges.Front()
42 | } else {
43 | it.cur = it.cur.Next()
44 | }
45 | return it.cur != nil
46 | }
47 |
48 | // Value returns the current time range.
49 | func (it *RangeIter) Value() Range {
50 | if it.cur == nil {
51 | return Range{}
52 | }
53 | return it.cur.Value.(Range)
54 | }
55 |
--------------------------------------------------------------------------------
/time/range_iter_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 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 time
22 |
23 | import (
24 | "container/list"
25 | "testing"
26 | "time"
27 |
28 | "github.com/stretchr/testify/require"
29 | )
30 |
31 | var (
32 | testTimeRanges = []Range{
33 | {Start: testStart, End: testStart.Add(time.Second)},
34 | {Start: testStart.Add(2 * time.Second), End: testStart.Add(10 * time.Second)},
35 | {Start: testStart.Add(20 * time.Second), End: testStart.Add(25 * time.Second)},
36 | }
37 | )
38 |
39 | func getTestList() *list.List {
40 | l := list.New()
41 | for _, r := range testTimeRanges {
42 | l.PushBack(r)
43 | }
44 | return l
45 | }
46 |
47 | func TestRangeIter(t *testing.T) {
48 | it := newRangeIter(nil)
49 | require.False(t, it.Next())
50 |
51 | it = newRangeIter(getTestList())
52 | for i := 0; i < len(testTimeRanges); i++ {
53 | require.True(t, it.Next())
54 | require.Equal(t, testTimeRanges[i], it.Value())
55 | }
56 | require.False(t, it.Next())
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/time/time.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 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 time implement facilities for working with time.
22 | package time
23 |
24 | import "time"
25 |
26 | const (
27 | nanosPerMillis = int64(time.Millisecond)
28 | )
29 |
30 | // ToNormalizedTime returns the normalized units of time given a time unit.
31 | func ToNormalizedTime(t time.Time, u time.Duration) int64 {
32 | return t.UnixNano() / u.Nanoseconds()
33 | }
34 |
35 | // FromNormalizedTime returns the time given the normalized time units and the time unit.
36 | func FromNormalizedTime(nt int64, u time.Duration) time.Time {
37 | return time.Unix(0, int64(u/time.Nanosecond)*nt)
38 | }
39 |
40 | // ToNormalizedDuration returns the normalized units of duration given a time unit.
41 | func ToNormalizedDuration(d time.Duration, u time.Duration) int64 {
42 | return int64(d / u)
43 | }
44 |
45 | // FromNormalizedDuration returns the duration given the normalized time duration and a time unit.
46 | func FromNormalizedDuration(nd int64, u time.Duration) time.Duration {
47 | return time.Duration(nd) * u
48 | }
49 |
50 | // ToNanoseconds converts a time to nanoseconds.
51 | func ToNanoseconds(t time.Time) int64 {
52 | return t.UnixNano()
53 | }
54 |
55 | // FromNanoseconds converts nanoseconds to a time.
56 | func FromNanoseconds(nsecs int64) time.Time {
57 | return time.Unix(0, nsecs)
58 | }
59 |
60 | // ToUnixMillis converts a time to milliseconds since Unix epoch
61 | func ToUnixMillis(t time.Time) int64 {
62 | return t.UnixNano() / nanosPerMillis
63 | }
64 |
65 | // FromUnixMillis converts milliseconds since Unix epoch to a time
66 | func FromUnixMillis(ms int64) time.Time {
67 | return time.Unix(0, ms*nanosPerMillis)
68 | }
69 |
70 | // Ceil returns the result of rounding t up to a multiple of d since
71 | // the zero time.
72 | func Ceil(t time.Time, d time.Duration) time.Time {
73 | res := t.Truncate(d)
74 | if res.Before(t) {
75 | res = res.Add(d)
76 | }
77 | return res
78 | }
79 |
80 | // MinTime returns the earlier one of t1 and t2.
81 | func MinTime(t1, t2 time.Time) time.Time {
82 | if t1.Before(t2) {
83 | return t1
84 | }
85 | return t2
86 | }
87 |
88 | // MaxTime returns the later one of t1 and t2.
89 | func MaxTime(t1, t2 time.Time) time.Time {
90 | if t1.After(t2) {
91 | return t1
92 | }
93 | return t2
94 | }
95 |
--------------------------------------------------------------------------------
/time/unix_nano.go:
--------------------------------------------------------------------------------
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 time
22 |
23 | import "time"
24 |
25 | // UnixNano is used to indicate that an int64 stores a unix timestamp at
26 | // nanosecond resolution
27 | type UnixNano int64
28 |
29 | // ToTime returns a time.ToTime from a UnixNano
30 | func (u UnixNano) ToTime() time.Time {
31 | return time.Unix(0, int64(u))
32 | }
33 |
34 | // ToUnixNano returns a UnixNano from a time.Time
35 | func ToUnixNano(t time.Time) UnixNano {
36 | return UnixNano(t.UnixNano())
37 | }
38 |
39 | // Before reports whether the time instant u is before t.
40 | func (u UnixNano) Before(t UnixNano) bool {
41 | return u < t
42 | }
43 |
44 | // After reports whether the time instant u is after t.
45 | func (u UnixNano) After(t UnixNano) bool {
46 | return u > t
47 | }
48 |
49 | // Equal reports whether the time instant u is equal to t.
50 | func (u UnixNano) Equal(t UnixNano) bool {
51 | return u == t
52 | }
53 |
--------------------------------------------------------------------------------
/time/unix_nano_test.go:
--------------------------------------------------------------------------------
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 time
22 |
23 | import (
24 | "testing"
25 | "time"
26 |
27 | "github.com/stretchr/testify/require"
28 | )
29 |
30 | func TestUnixNano(t *testing.T) {
31 | time := time.Unix(0, 1000)
32 | unixNano := ToUnixNano(time)
33 | require.Equal(t, UnixNano(1000), unixNano)
34 | require.Equal(t, time, unixNano.ToTime())
35 | }
36 |
37 | func TestUnixNanoBefore(t *testing.T) {
38 | t0 := UnixNano(0)
39 | t1 := UnixNano(1)
40 |
41 | require.Equal(t, true, t0.Before(t1))
42 | require.Equal(t, false, t1.Before(t0))
43 | require.Equal(t, false, t0.Before(t0))
44 | }
45 |
46 | func TestUnixNanoAfter(t *testing.T) {
47 | t0 := UnixNano(0)
48 | t1 := UnixNano(1)
49 |
50 | require.Equal(t, false, t0.After(t1))
51 | require.Equal(t, true, t1.After(t0))
52 | require.Equal(t, false, t0.After(t0))
53 | }
54 |
55 | func TestUnixNanoEqual(t *testing.T) {
56 | t0 := UnixNano(0)
57 | t1 := UnixNano(1)
58 |
59 | require.Equal(t, false, t0.Equal(t1))
60 | require.Equal(t, false, t1.Equal(t0))
61 | require.Equal(t, true, t0.Equal(t0))
62 | }
63 |
--------------------------------------------------------------------------------
/unsafe/bytes_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2019 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 unsafe
22 |
23 | import (
24 | "bytes"
25 | "testing"
26 |
27 | "github.com/stretchr/testify/require"
28 | )
29 |
30 | func TestWithStringSmallString(t *testing.T) {
31 | str := []byte("foobarbaz")
32 | validateWithString(t, str)
33 | }
34 |
35 | func TestWithStringLargeString(t *testing.T) {
36 | var buf bytes.Buffer
37 | for i := 0; i < 65536; i++ {
38 | buf.WriteByte(byte(i % 256))
39 | }
40 | str := buf.Bytes()
41 | validateWithString(t, str)
42 | }
43 |
44 | func TestWithStringAndArgSmallString(t *testing.T) {
45 | str := []byte("foobarbaz")
46 | validateWithStringAndArg(t, str)
47 | }
48 |
49 | func TestWithStringAndArgLargeString(t *testing.T) {
50 | var buf bytes.Buffer
51 | for i := 0; i < 65536; i++ {
52 | buf.WriteByte(byte(i % 256))
53 | }
54 | str := buf.Bytes()
55 | validateWithStringAndArg(t, str)
56 | }
57 |
58 | var withStringBenchSink string
59 |
60 | func BenchmarkWithString(b *testing.B) {
61 | str := []byte("foobarbaz")
62 | WithString(str, func(s string) {
63 | withStringBenchSink = s
64 | })
65 | }
66 |
67 | func validateWithString(t *testing.T, b []byte) {
68 | WithString(b, func(str string) {
69 | require.Equal(t, []byte(str), []byte(b))
70 | require.Equal(t, len(str), len(b))
71 | })
72 | }
73 |
74 | func validateWithStringAndArg(t *testing.T, b []byte) {
75 | WithStringAndArg(b, "cat", func(str string, arg interface{}) {
76 | var buf bytes.Buffer
77 | buf.WriteString(str)
78 | buf.WriteString(arg.(string))
79 | require.Equal(t, string(b)+"cat", buf.String())
80 | })
81 | }
82 |
--------------------------------------------------------------------------------
/unsafe/string_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 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 unsafe
22 |
23 | import (
24 | "bytes"
25 | "testing"
26 |
27 | "github.com/stretchr/testify/require"
28 | )
29 |
30 | func TestWithBytesSmallString(t *testing.T) {
31 | str := "foobarbaz"
32 | validateWithBytes(t, str)
33 | }
34 |
35 | func TestWithBytesLargeString(t *testing.T) {
36 | var buf bytes.Buffer
37 | for i := 0; i < 65536; i++ {
38 | buf.WriteByte(byte(i % 256))
39 | }
40 | str := buf.String()
41 | validateWithBytes(t, str)
42 | }
43 |
44 | func TestWithBytesAndArgSmallString(t *testing.T) {
45 | str := "foobarbaz"
46 | validateWithBytesAndArg(t, str)
47 | }
48 |
49 | func TestWithBytesAndArgLargeString(t *testing.T) {
50 | var buf bytes.Buffer
51 | for i := 0; i < 65536; i++ {
52 | buf.WriteByte(byte(i % 256))
53 | }
54 | str := buf.String()
55 | validateWithBytesAndArg(t, str)
56 | }
57 |
58 | var withBytesBenchSink ImmutableBytes
59 |
60 | func BenchmarkWithBytes(b *testing.B) {
61 | for i := 0; i < b.N; i++ {
62 | WithBytes("foobar", func(b ImmutableBytes) {
63 | withBytesBenchSink = b
64 | })
65 | }
66 | }
67 |
68 | func validateWithBytes(t *testing.T, str string) {
69 | WithBytes(str, func(b ImmutableBytes) {
70 | require.Equal(t, []byte(str), []byte(b))
71 | require.Equal(t, len(str), len(b))
72 | require.Equal(t, len(str), cap(b))
73 | })
74 | }
75 |
76 | func validateWithBytesAndArg(t *testing.T, str string) {
77 | WithBytesAndArg(str, "cat", func(data ImmutableBytes, arg interface{}) {
78 | var buf bytes.Buffer
79 | for _, b := range data {
80 | buf.WriteByte(b)
81 | }
82 | buf.WriteString(arg.(string))
83 | require.Equal(t, str+"cat", buf.String())
84 | })
85 | }
86 |
--------------------------------------------------------------------------------
/watch/source.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 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 watch
22 |
23 | import (
24 | "errors"
25 | "sync"
26 |
27 | "github.com/m3db/m3x/close"
28 | "github.com/m3db/m3x/log"
29 | )
30 |
31 | // ErrSourceClosed indicates that the Source should be closed.
32 | var ErrSourceClosed = errors.New("source closed")
33 |
34 | // SourceInput provides data for Source,
35 | type SourceInput interface {
36 | // Poll will be called by Source for data. Any backoff/jitter logic should
37 | // be handled here.
38 | Poll() (interface{}, error)
39 | }
40 |
41 | // Source polls data by calling SourcePollFn and notifies its watches on updates.
42 | type Source interface {
43 | close.SimpleCloser
44 |
45 | // Get returns the latest value.
46 | Get() interface{}
47 |
48 | // Watch returns the value and a Watch.
49 | Watch() (interface{}, Watch, error)
50 | }
51 |
52 | // NewSource returns a new Source.
53 | func NewSource(input SourceInput, logger log.Logger) Source {
54 | s := &source{
55 | input: input,
56 | w: NewWatchable(),
57 | logger: logger,
58 | }
59 |
60 | go s.run()
61 | return s
62 | }
63 |
64 | type source struct {
65 | sync.RWMutex
66 |
67 | input SourceInput
68 | w Watchable
69 | closed bool
70 | logger log.Logger
71 | }
72 |
73 | func (s *source) run() {
74 | for !s.isClosed() {
75 | data, err := s.input.Poll()
76 | if err == ErrSourceClosed {
77 | s.logger.Errorf("watch source upstream is closed")
78 | s.Close()
79 | return
80 | }
81 | if err != nil {
82 | s.logger.Errorf("watch source poll error: %v", err)
83 | continue
84 | }
85 |
86 | if err = s.w.Update(data); err != nil {
87 | s.logger.Errorf("watch source update error: %v", err)
88 | }
89 | }
90 | }
91 |
92 | func (s *source) isClosed() bool {
93 | s.RLock()
94 | defer s.RUnlock()
95 | return s.closed
96 | }
97 |
98 | func (s *source) Close() {
99 | s.Lock()
100 | defer s.Unlock()
101 | if s.closed {
102 | return
103 | }
104 | s.closed = true
105 | s.w.Close()
106 | }
107 |
108 | func (s *source) Get() interface{} {
109 | return s.w.Get()
110 | }
111 |
112 | func (s *source) Watch() (interface{}, Watch, error) {
113 | return s.w.Watch()
114 | }
115 |
--------------------------------------------------------------------------------