Skip to content

Commit 1fc18c2

Browse files
author
Steffen Siering
authored
Init package libbeat/statestore (#19117)
Initialize support for the statestore package. The addition of the statestore package is split up into multiple changeset to ease review. The final version of the package can be found [here](https://github.com/urso/beats/tree/fb-input-v2-combined/libbeat/statestore). Once finalized, the libbeat/statestore package contains: - The statestore frontend and interface for use within Beats - Interfaces for the store backend - A common set of tests store backends need to support - a storetest package for testing new features that require a store. The testing helpers use map[string]interface{} that can be initialized or queried after the test run for validation purposes. - The default memlog backend + tests This change includes the frontend and backend interfaces only. Once merged we will add the tests and finally the memlog store.
1 parent eaf5e2f commit 1fc18c2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+3778
-1073
lines changed

NOTICE.txt

+46-2
Original file line numberDiff line numberDiff line change
@@ -1911,6 +1911,15 @@ SOFTWARE
19111911
6.11 "Subscription" means the right to receive Support Services and a License
19121912
to the Commercial Software.
19131913

1914+
--------------------------------------------------------------------
1915+
Dependency: github.com/elastic/go-concert
1916+
Version: v0.0.2
1917+
License type (autodetected): Apache-2.0
1918+
./vendor/github.com/elastic/go-concert/LICENSE:
1919+
--------------------------------------------------------------------
1920+
Apache License 2.0
1921+
1922+
19141923
--------------------------------------------------------------------
19151924
Dependency: github.com/elastic/go-libaudit/v2
19161925
Version: v2.0.0
@@ -8135,7 +8144,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
81358144

81368145
--------------------------------------------------------------------
81378146
Dependency: golang.org/x/lint
8138-
Revision: fdd1cda4f05f
8147+
Revision: 910be7a94367
81398148
License type (autodetected): BSD-3-Clause
81408149
./vendor/golang.org/x/lint/LICENSE:
81418150
--------------------------------------------------------------------
@@ -8167,6 +8176,41 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
81678176
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
81688177
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
81698178

8179+
--------------------------------------------------------------------
8180+
Dependency: golang.org/x/mod
8181+
Version: v0.1.1
8182+
Revision: c90efee705ee
8183+
License type (autodetected): BSD-3-Clause
8184+
./vendor/golang.org/x/mod/LICENSE:
8185+
--------------------------------------------------------------------
8186+
Copyright (c) 2009 The Go Authors. All rights reserved.
8187+
8188+
Redistribution and use in source and binary forms, with or without
8189+
modification, are permitted provided that the following conditions are
8190+
met:
8191+
8192+
* Redistributions of source code must retain the above copyright
8193+
notice, this list of conditions and the following disclaimer.
8194+
* Redistributions in binary form must reproduce the above
8195+
copyright notice, this list of conditions and the following disclaimer
8196+
in the documentation and/or other materials provided with the
8197+
distribution.
8198+
* Neither the name of Google Inc. nor the names of its
8199+
contributors may be used to endorse or promote products derived from
8200+
this software without specific prior written permission.
8201+
8202+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
8203+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
8204+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
8205+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
8206+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8207+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
8208+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
8209+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
8210+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
8211+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
8212+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
8213+
81708214
--------------------------------------------------------------------
81718215
Dependency: golang.org/x/net
81728216
Revision: 16171245cfb2
@@ -8373,7 +8417,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
83738417

83748418
--------------------------------------------------------------------
83758419
Dependency: golang.org/x/tools
8376-
Revision: 7b8e75db28f4
8420+
Revision: b320d3a0f5a2
83778421
License type (autodetected): BSD-3-Clause
83788422
./vendor/golang.org/x/tools/LICENSE:
83798423
--------------------------------------------------------------------

go.mod

+3-2
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ require (
5858
github.com/eclipse/paho.mqtt.golang v1.2.1-0.20200121105743-0d940dd29fd2
5959
github.com/elastic/ecs v1.5.0
6060
github.com/elastic/elastic-agent-client/v7 v7.0.0-20200601155656-d6a9eb4f6d07
61+
github.com/elastic/go-concert v0.0.2
6162
github.com/elastic/go-libaudit/v2 v2.0.0-20200515221334-92371bef3fb8
6263
github.com/elastic/go-licenser v0.2.1
6364
github.com/elastic/go-lookslike v0.3.0
@@ -150,14 +151,14 @@ require (
150151
go.uber.org/multierr v1.3.0
151152
go.uber.org/zap v1.14.0
152153
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37
153-
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f
154+
golang.org/x/lint v0.0.0-20200130185559-910be7a94367
154155
golang.org/x/net v0.0.0-20200202094626-16171245cfb2
155156
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
156157
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
157158
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e
158159
golang.org/x/text v0.3.2
159160
golang.org/x/time v0.0.0-20191024005414-555d28b269f0
160-
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4
161+
golang.org/x/tools v0.0.0-20200216192241-b320d3a0f5a2
161162
google.golang.org/api v0.15.0
162163
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb
163164
google.golang.org/grpc v1.29.1

go.sum

+10
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,8 @@ github.com/elastic/elastic-agent-client/v7 v7.0.0-20200601155656-d6a9eb4f6d07 h1
227227
github.com/elastic/elastic-agent-client/v7 v7.0.0-20200601155656-d6a9eb4f6d07/go.mod h1:uh/Gj9a0XEbYoM4NYz4LvaBVARz3QXLmlNjsrKY9fTc=
228228
github.com/elastic/fsevents v0.0.0-20181029231046-e1d381a4d270 h1:cWPqxlPtir4RoQVCpGSRXmLqjEHpJKbR60rxh1nQZY4=
229229
github.com/elastic/fsevents v0.0.0-20181029231046-e1d381a4d270/go.mod h1:Msl1pdboCbArMF/nSCDUXgQuWTeoMmE/z8607X+k7ng=
230+
github.com/elastic/go-concert v0.0.2 h1:hJb9h99LS/lyjf7pE1wQ+eiNw+0CXVLCJR42yx+AvOQ=
231+
github.com/elastic/go-concert v0.0.2/go.mod h1:9MtFarjXroUgmm0m6HY3NSe1XiKhdktiNRRj9hWvIaM=
230232
github.com/elastic/go-libaudit/v2 v2.0.0-20200515221334-92371bef3fb8 h1:Jcnojiuok7Ea5hitJK9VWmBigganE2MMETOH0VZasEA=
231233
github.com/elastic/go-libaudit/v2 v2.0.0-20200515221334-92371bef3fb8/go.mod h1:j2CZcVcluWDGhQTnq1SOPy1NKEIa74FtQ39Nnz87Jxk=
232234
github.com/elastic/go-licenser v0.2.1 h1:K76YI6XR2LRpewLGwhrTqasXZcNJG2yHY4/jit/IXGY=
@@ -697,6 +699,7 @@ go.opencensus.io v0.22.2 h1:75k/FF0Q2YM8QYo07VPddOLBslDt1MZOdEslOHvmzAs=
697699
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
698700
go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY=
699701
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
702+
go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
700703
go.uber.org/multierr v1.3.0 h1:sFPn2GLc3poCkfrpIXGhBD2X0CMIo4Q/zSULXrj/+uc=
701704
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
702705
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
@@ -735,10 +738,13 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl
735738
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
736739
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE=
737740
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
741+
golang.org/x/lint v0.0.0-20200130185559-910be7a94367 h1:0IiAsCRByjO2QjX7ZPkw5oU9x+n1YqRL802rjC0c3Aw=
742+
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
738743
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
739744
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
740745
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
741746
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
747+
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E=
742748
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
743749
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
744750
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -843,9 +849,13 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn
843849
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
844850
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
845851
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
852+
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
846853
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
847854
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4 h1:Toz2IK7k8rbltAXwNAxKcn9OzqyNfMUhUNjz3sL0NMk=
848855
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
856+
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
857+
golang.org/x/tools v0.0.0-20200216192241-b320d3a0f5a2 h1:0sfSpGSa544Fwnbot3Oxq/U6SXqjty6Jy/3wRhVS7ig=
858+
golang.org/x/tools v0.0.0-20200216192241-b320d3a0f5a2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
849859
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
850860
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
851861
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=

libbeat/statestore/backend/backend.go

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Licensed to Elasticsearch B.V. under one or more contributor
2+
// license agreements. See the NOTICE file distributed with
3+
// this work for additional information regarding copyright
4+
// ownership. Elasticsearch B.V. licenses this file to you under
5+
// the Apache License, Version 2.0 (the "License"); you may
6+
// not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package backend
19+
20+
// Registry provides access to stores managed by the backend storage.
21+
type Registry interface {
22+
// Access opens a store. The store will be closed by the frontend, once all
23+
// accessed stores have been closed.
24+
//
25+
// The Store instance returned must be threadsafe.
26+
Access(name string) (Store, error)
27+
28+
// Close is called on shutdown after all stores have been closed.
29+
// An implementation of Registry is not required to check for the stores to be closed.
30+
Close() error
31+
}
32+
33+
// ValueDecoder is used to decode values into go structs or maps within a transaction.
34+
// A ValueDecoder is supposed to be invalidated by beats after the loop operations has returned.
35+
type ValueDecoder interface {
36+
Decode(to interface{}) error
37+
}
38+
39+
// Store provides access to key value pairs.
40+
type Store interface {
41+
// Close should close the store and release all used resources.
42+
Close() error
43+
44+
// Has checks if the key exists. No error must be returned if the key does
45+
// not exists, but the bool return must be false.
46+
// An error return value must indicate internal errors only. The store is
47+
// assumed to be in a 'bad' but recoverable state if 'Has' fails.
48+
Has(key string) (bool, error)
49+
50+
// Get decodes the value for the given key into value.
51+
// Besides internal implementation specific errors an error is assumed
52+
// to be returned if the key does not exist or the type of the value
53+
// passed is incompatible to the actual value in the store (decoding error).
54+
Get(key string, value interface{}) error
55+
56+
// Set inserts or overwrites a key pair in the store.
57+
// The `value` parameters can be assumed to be a struct or a map. Besides
58+
// internal implementation specific errors, an error should be returned if
59+
// the value given can not be encoded.
60+
Set(key string, value interface{}) error
61+
62+
// Remove removes and entry from the store.
63+
Remove(string) error
64+
65+
// Each loops over all key value pairs in the store calling fn for each pair.
66+
// The ValueDecoder is used by fn to optionally decode the value into a
67+
// custom struct or map. The decoder must be executable multiple times, but
68+
// is assumed to be invalidated once fn returns
69+
// The loop shall return if fn returns an error or false.
70+
Each(fn func(string, ValueDecoder) (bool, error)) error
71+
}

libbeat/statestore/error.go

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// Licensed to Elasticsearch B.V. under one or more contributor
2+
// license agreements. See the NOTICE file distributed with
3+
// this work for additional information regarding copyright
4+
// ownership. Elasticsearch B.V. licenses this file to you under
5+
// the Apache License, Version 2.0 (the "License"); you may
6+
// not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package statestore
19+
20+
import (
21+
"errors"
22+
"fmt"
23+
)
24+
25+
// ErrorAccess indicates that an error occured when trying to open a Store.
26+
type ErrorAccess struct {
27+
name string
28+
cause error
29+
}
30+
31+
// Store reports the name of the store that could not been accessed.
32+
func (e *ErrorAccess) Store() string { return e.name }
33+
34+
// Unwrap returns the cause for the error or nil if the cause is unknown or has
35+
// not been reported by the backend
36+
func (e *ErrorAccess) Unwrap() error { return e.cause }
37+
38+
// Error creates a descriptive error string.
39+
func (e *ErrorAccess) Error() string {
40+
if e.cause == nil {
41+
return fmt.Sprintf("failed to open store '%v'", e.name)
42+
}
43+
return fmt.Sprintf("failed to open store '%v': %v", e.name, e.cause)
44+
}
45+
46+
// ErrorClosed indicates that the operation failed because the store has already been closed.
47+
type ErrorClosed struct {
48+
name string
49+
operation string
50+
}
51+
52+
// Store reports the name of the store that has been closed.
53+
func (e *ErrorClosed) Store() string { return e.name }
54+
55+
// Operation returns a 'readable' name for the operation that failed to access the closed store.
56+
func (e *ErrorClosed) Operation() string { return e.operation }
57+
58+
// Error creates a descriptive error string.
59+
func (e *ErrorClosed) Error() string {
60+
return fmt.Sprintf("can not executed %v operation on closed store '%v'", e.operation, e.name)
61+
}
62+
63+
// ErrorOperation is returned when a generic store operation failed.
64+
type ErrorOperation struct {
65+
name string
66+
operation string
67+
cause error
68+
}
69+
70+
// Store reports the name of the store.
71+
func (e *ErrorOperation) Store() string { return e.name }
72+
73+
// Operation returns a 'readable' name for the operation that failed.
74+
func (e *ErrorOperation) Operation() string { return e.operation }
75+
76+
// Unwrap returns the cause of the failure.
77+
func (e *ErrorOperation) Unwrap() error { return e.cause }
78+
79+
// Error creates a descriptive error string.
80+
func (e *ErrorOperation) Error() string {
81+
return fmt.Sprintf("failed in %v operation on store '%v': %v", e.operation, e.name, e.cause)
82+
}
83+
84+
// IsClosed returns true if the cause for an Error is ErrorClosed.
85+
func IsClosed(err error) bool {
86+
var tmp *ErrorClosed
87+
if errors.As(err, &tmp) {
88+
return true
89+
}
90+
return false
91+
}

libbeat/statestore/registry.go

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Licensed to Elasticsearch B.V. under one or more contributor
2+
// license agreements. See the NOTICE file distributed with
3+
// this work for additional information regarding copyright
4+
// ownership. Elasticsearch B.V. licenses this file to you under
5+
// the Apache License, Version 2.0 (the "License"); you may
6+
// not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package statestore
19+
20+
import (
21+
"sync"
22+
23+
"github.com/elastic/beats/v7/libbeat/statestore/backend"
24+
)
25+
26+
// Registry manages multiple key-value stores.
27+
// When working with a registry, one must access a store. Depending on backend
28+
// a store can be an index, a table, or a directory. All access to a store is
29+
// handled by transaction.
30+
type Registry struct {
31+
backend backend.Registry
32+
33+
mu sync.Mutex
34+
active map[string]*sharedStore // active/open stores
35+
wg sync.WaitGroup
36+
}
37+
38+
// ValueDecoder is used to decode retrieved from an actual store. A
39+
// ValueDecoder instance is valid for the lifetime of the transaction only.
40+
type ValueDecoder = backend.ValueDecoder
41+
42+
// NewRegistry creates a new Registry with a configured backend.
43+
func NewRegistry(backend backend.Registry) *Registry {
44+
return &Registry{
45+
backend: backend,
46+
active: map[string]*sharedStore{},
47+
}
48+
}
49+
50+
// Close closes the backend storage. Close blocks until all stores in use are closed.
51+
func (r *Registry) Close() error {
52+
r.wg.Wait() // wait for all stores being closed
53+
return r.backend.Close()
54+
}
55+
56+
// Get opens a shared store. A store is closed and released only after all it's
57+
// users have closed the store.
58+
func (r *Registry) Get(name string) (*Store, error) {
59+
r.mu.Lock()
60+
defer r.mu.Unlock()
61+
62+
shared := r.active[name]
63+
if shared == nil {
64+
backend, err := r.backend.Access(name)
65+
if err != nil {
66+
return nil, &ErrorAccess{name: name, cause: err}
67+
}
68+
69+
shared = newSharedStore(r, name, backend)
70+
defer shared.Release()
71+
72+
r.active[name] = shared
73+
r.wg.Add(1)
74+
}
75+
76+
return newStore(shared), nil
77+
}
78+
79+
func (r *Registry) unregisterStore(s *sharedStore) {
80+
_, exists := r.active[s.name]
81+
if !exists {
82+
panic("removing an unknown store")
83+
}
84+
85+
delete(r.active, s.name)
86+
r.wg.Done()
87+
}

0 commit comments

Comments
 (0)