vendor: github.com/hashicorp/go-memdb v1.3.5
| ... | ... |
@@ -48,7 +48,7 @@ require ( |
| 48 | 48 |
github.com/google/uuid v1.6.0 |
| 49 | 49 |
github.com/gorilla/mux v1.8.1 |
| 50 | 50 |
github.com/hashicorp/go-immutable-radix/v2 v2.1.0 |
| 51 |
- github.com/hashicorp/go-memdb v1.3.2 |
|
| 51 |
+ github.com/hashicorp/go-memdb v1.3.5 |
|
| 52 | 52 |
github.com/hashicorp/memberlist v0.4.0 |
| 53 | 53 |
github.com/hashicorp/serf v0.8.5 |
| 54 | 54 |
github.com/ishidawataru/sctp v0.0.0-20250829011129-4b890084db30 |
| ... | ... |
@@ -296,13 +296,12 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY |
| 296 | 296 |
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= |
| 297 | 297 |
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= |
| 298 | 298 |
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= |
| 299 |
-github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= |
|
| 300 | 299 |
github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= |
| 301 | 300 |
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= |
| 302 | 301 |
github.com/hashicorp/go-immutable-radix/v2 v2.1.0 h1:CUW5RYIcysz+D3B+l1mDeXrQ7fUvGGCwJfdASSzbrfo= |
| 303 | 302 |
github.com/hashicorp/go-immutable-radix/v2 v2.1.0/go.mod h1:hgdqLXA4f6NIjRVisM1TJ9aOJVNRqKZj+xDGF6m7PBw= |
| 304 |
-github.com/hashicorp/go-memdb v1.3.2 h1:RBKHOsnSszpU6vxq80LzC2BaQjuuvoyaQbkLTf7V7g8= |
|
| 305 |
-github.com/hashicorp/go-memdb v1.3.2/go.mod h1:Mluclgwib3R93Hk5fxEfiRhB+6Dar64wWh71LpNSe3g= |
|
| 303 |
+github.com/hashicorp/go-memdb v1.3.5 h1:b3taDMxCBCBVgyRrS1AZVHO14ubMYZB++QpNhBg+Nyo= |
|
| 304 |
+github.com/hashicorp/go-memdb v1.3.5/go.mod h1:8IVKKBkVe+fxFgdFOYxzQQNjz+sWCyHCdIC/+5+Vy1Y= |
|
| 306 | 305 |
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= |
| 307 | 306 |
github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= |
| 308 | 307 |
github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= |
| 309 | 308 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,13 @@ |
| 0 |
+# Each line is a file pattern followed by one or more owners. |
|
| 1 |
+# More on CODEOWNERS files: https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners |
|
| 2 |
+ |
|
| 3 |
+# Default owner |
|
| 4 |
+* @hashicorp/team-ip-compliance @hashicorp/raft-force |
|
| 5 |
+ |
|
| 6 |
+# Add override rules below. Each line is a file/folder pattern followed by one or more owners. |
|
| 7 |
+# Being an owner means those groups or individuals will be added as reviewers to PRs affecting |
|
| 8 |
+# those areas of the code. |
|
| 9 |
+# Examples: |
|
| 10 |
+# /docs/ @docs-team |
|
| 11 |
+# *.js @js-team |
|
| 12 |
+# *.go @go-team |
| ... | ... |
@@ -1,3 +1,6 @@ |
| 1 |
+// Copyright (c) HashiCorp, Inc. |
|
| 2 |
+// SPDX-License-Identifier: MPL-2.0 |
|
| 3 |
+ |
|
| 1 | 4 |
package memdb |
| 2 | 5 |
|
| 3 | 6 |
import ( |
| ... | ... |
@@ -5,8 +8,8 @@ import ( |
| 5 | 5 |
"encoding/hex" |
| 6 | 6 |
"errors" |
| 7 | 7 |
"fmt" |
| 8 |
- "math/bits" |
|
| 9 | 8 |
"reflect" |
| 9 |
+ "strconv" |
|
| 10 | 10 |
"strings" |
| 11 | 11 |
) |
| 12 | 12 |
|
| ... | ... |
@@ -308,8 +311,7 @@ func (i *IntFieldIndex) FromObject(obj interface{}) (bool, []byte, error) {
|
| 308 | 308 |
|
| 309 | 309 |
// Get the value and encode it |
| 310 | 310 |
val := fv.Int() |
| 311 |
- buf := make([]byte, size) |
|
| 312 |
- binary.PutVarint(buf, val) |
|
| 311 |
+ buf := encodeInt(val, size) |
|
| 313 | 312 |
|
| 314 | 313 |
return true, buf, nil |
| 315 | 314 |
} |
| ... | ... |
@@ -331,26 +333,50 @@ func (i *IntFieldIndex) FromArgs(args ...interface{}) ([]byte, error) {
|
| 331 | 331 |
} |
| 332 | 332 |
|
| 333 | 333 |
val := v.Int() |
| 334 |
- buf := make([]byte, size) |
|
| 335 |
- binary.PutVarint(buf, val) |
|
| 334 |
+ buf := encodeInt(val, size) |
|
| 336 | 335 |
|
| 337 | 336 |
return buf, nil |
| 338 | 337 |
} |
| 339 | 338 |
|
| 339 |
+func encodeInt(val int64, size int) []byte {
|
|
| 340 |
+ buf := make([]byte, size) |
|
| 341 |
+ |
|
| 342 |
+ // This bit flips the sign bit on any sized signed twos-complement integer, |
|
| 343 |
+ // which when truncated to a uint of the same size will bias the value such |
|
| 344 |
+ // that the maximum negative int becomes 0, and the maximum positive int |
|
| 345 |
+ // becomes the maximum positive uint. |
|
| 346 |
+ scaled := val ^ int64(-1<<(size*8-1)) |
|
| 347 |
+ |
|
| 348 |
+ switch size {
|
|
| 349 |
+ case 1: |
|
| 350 |
+ buf[0] = uint8(scaled) |
|
| 351 |
+ case 2: |
|
| 352 |
+ binary.BigEndian.PutUint16(buf, uint16(scaled)) |
|
| 353 |
+ case 4: |
|
| 354 |
+ binary.BigEndian.PutUint32(buf, uint32(scaled)) |
|
| 355 |
+ case 8: |
|
| 356 |
+ binary.BigEndian.PutUint64(buf, uint64(scaled)) |
|
| 357 |
+ default: |
|
| 358 |
+ panic(fmt.Sprintf("unsupported int size parameter: %d", size))
|
|
| 359 |
+ } |
|
| 360 |
+ |
|
| 361 |
+ return buf |
|
| 362 |
+} |
|
| 363 |
+ |
|
| 340 | 364 |
// IsIntType returns whether the passed type is a type of int and the number |
| 341 | 365 |
// of bytes needed to encode the type. |
| 342 | 366 |
func IsIntType(k reflect.Kind) (size int, okay bool) {
|
| 343 | 367 |
switch k {
|
| 344 | 368 |
case reflect.Int: |
| 345 |
- return binary.MaxVarintLen64, true |
|
| 369 |
+ return strconv.IntSize / 8, true |
|
| 346 | 370 |
case reflect.Int8: |
| 347 |
- return 2, true |
|
| 371 |
+ return 1, true |
|
| 348 | 372 |
case reflect.Int16: |
| 349 |
- return binary.MaxVarintLen16, true |
|
| 373 |
+ return 2, true |
|
| 350 | 374 |
case reflect.Int32: |
| 351 |
- return binary.MaxVarintLen32, true |
|
| 375 |
+ return 4, true |
|
| 352 | 376 |
case reflect.Int64: |
| 353 |
- return binary.MaxVarintLen64, true |
|
| 377 |
+ return 8, true |
|
| 354 | 378 |
default: |
| 355 | 379 |
return 0, false |
| 356 | 380 |
} |
| ... | ... |
@@ -420,6 +446,8 @@ func encodeUInt(val uint64, size int) []byte {
|
| 420 | 420 |
binary.BigEndian.PutUint32(buf, uint32(val)) |
| 421 | 421 |
case 8: |
| 422 | 422 |
binary.BigEndian.PutUint64(buf, val) |
| 423 |
+ default: |
|
| 424 |
+ panic(fmt.Sprintf("unsupported uint size parameter: %d", size))
|
|
| 423 | 425 |
} |
| 424 | 426 |
|
| 425 | 427 |
return buf |
| ... | ... |
@@ -430,7 +458,7 @@ func encodeUInt(val uint64, size int) []byte {
|
| 430 | 430 |
func IsUintType(k reflect.Kind) (size int, okay bool) {
|
| 431 | 431 |
switch k {
|
| 432 | 432 |
case reflect.Uint: |
| 433 |
- return bits.UintSize / 8, true |
|
| 433 |
+ return strconv.IntSize / 8, true |
|
| 434 | 434 |
case reflect.Uint8: |
| 435 | 435 |
return 1, true |
| 436 | 436 |
case reflect.Uint16: |
| ... | ... |
@@ -767,8 +795,6 @@ type CompoundMultiIndex struct {
|
| 767 | 767 |
func (c *CompoundMultiIndex) FromObject(raw interface{}) (bool, [][]byte, error) {
|
| 768 | 768 |
// At each entry, builder is storing the results from the next index |
| 769 | 769 |
builder := make([][][]byte, 0, len(c.Indexes)) |
| 770 |
- // Start with something higher to avoid resizing if possible |
|
| 771 |
- out := make([][]byte, 0, len(c.Indexes)^3) |
|
| 772 | 770 |
|
| 773 | 771 |
forloop: |
| 774 | 772 |
// This loop goes through each indexer and adds the value(s) provided to the next |
| ... | ... |
@@ -810,6 +836,9 @@ forloop: |
| 810 | 810 |
} |
| 811 | 811 |
} |
| 812 | 812 |
|
| 813 |
+ // Start with something higher to avoid resizing if possible |
|
| 814 |
+ out := make([][]byte, 0, len(c.Indexes)^3) |
|
| 815 |
+ |
|
| 813 | 816 |
// We are walking through the builder slice essentially in a depth-first fashion, |
| 814 | 817 |
// building the prefix and leaves as we go. If AllowMissing is false, we only insert |
| 815 | 818 |
// these full paths to leaves. Otherwise, we also insert each prefix along the way. |
| ... | ... |
@@ -818,10 +847,16 @@ forloop: |
| 818 | 818 |
// field specified as "abc", it is valid to call FromArgs with just "abc". |
| 819 | 819 |
var walkVals func([]byte, int) |
| 820 | 820 |
walkVals = func(currPrefix []byte, depth int) {
|
| 821 |
+ if depth >= len(builder) {
|
|
| 822 |
+ return |
|
| 823 |
+ } |
|
| 824 |
+ |
|
| 821 | 825 |
if depth == len(builder)-1 {
|
| 822 | 826 |
// These are the "leaves", so append directly |
| 823 | 827 |
for _, v := range builder[depth] {
|
| 824 |
- out = append(out, append(currPrefix, v...)) |
|
| 828 |
+ outcome := make([]byte, len(currPrefix)) |
|
| 829 |
+ copy(outcome, currPrefix) |
|
| 830 |
+ out = append(out, append(outcome, v...)) |
|
| 825 | 831 |
} |
| 826 | 832 |
return |
| 827 | 833 |
} |
| ... | ... |
@@ -1,3 +1,6 @@ |
| 1 |
+// Copyright (c) HashiCorp, Inc. |
|
| 2 |
+// SPDX-License-Identifier: MPL-2.0 |
|
| 3 |
+ |
|
| 1 | 4 |
// Package memdb provides an in-memory database that supports transactions |
| 2 | 5 |
// and MVCC. |
| 3 | 6 |
package memdb |
| ... | ... |
@@ -52,6 +55,14 @@ func NewMemDB(schema *DBSchema) (*MemDB, error) {
|
| 52 | 52 |
return db, nil |
| 53 | 53 |
} |
| 54 | 54 |
|
| 55 |
+// DBSchema returns schema in use for introspection. |
|
| 56 |
+// |
|
| 57 |
+// The method is intended for *read-only* debugging use cases, |
|
| 58 |
+// returned schema should *never be modified in-place*. |
|
| 59 |
+func (db *MemDB) DBSchema() *DBSchema {
|
|
| 60 |
+ return db.schema |
|
| 61 |
+} |
|
| 62 |
+ |
|
| 55 | 63 |
// getRoot is used to do an atomic load of the root pointer |
| 56 | 64 |
func (db *MemDB) getRoot() *iradix.Tree {
|
| 57 | 65 |
root := (*iradix.Tree)(atomic.LoadPointer(&db.root)) |
| ... | ... |
@@ -1,3 +1,6 @@ |
| 1 |
+// Copyright (c) HashiCorp, Inc. |
|
| 2 |
+// SPDX-License-Identifier: MPL-2.0 |
|
| 3 |
+ |
|
| 1 | 4 |
package memdb |
| 2 | 5 |
|
| 3 | 6 |
import ( |
| ... | ... |
@@ -102,7 +105,8 @@ func (txn *Txn) writableIndex(table, index string) *iradix.Txn {
|
| 102 | 102 |
} |
| 103 | 103 |
|
| 104 | 104 |
// Abort is used to cancel this transaction. |
| 105 |
-// This is a noop for read transactions. |
|
| 105 |
+// This is a noop for read transactions, |
|
| 106 |
+// already aborted or commited transactions. |
|
| 106 | 107 |
func (txn *Txn) Abort() {
|
| 107 | 108 |
// Noop for a read transaction |
| 108 | 109 |
if !txn.write {
|
| ... | ... |
@@ -124,7 +128,8 @@ func (txn *Txn) Abort() {
|
| 124 | 124 |
} |
| 125 | 125 |
|
| 126 | 126 |
// Commit is used to finalize this transaction. |
| 127 |
-// This is a noop for read transactions. |
|
| 127 |
+// This is a noop for read transactions, |
|
| 128 |
+// already aborted or committed transactions. |
|
| 128 | 129 |
func (txn *Txn) Commit() {
|
| 129 | 130 |
// Noop for a read transaction |
| 130 | 131 |
if !txn.write {
|
| ... | ... |
@@ -321,7 +326,7 @@ func (txn *Txn) Delete(table string, obj interface{}) error {
|
| 321 | 321 |
return fmt.Errorf("object missing primary index")
|
| 322 | 322 |
} |
| 323 | 323 |
|
| 324 |
- // Lookup the object by ID first, check fi we should continue |
|
| 324 |
+ // Lookup the object by ID first, check if we should continue |
|
| 325 | 325 |
idTxn := txn.writableIndex(table, id) |
| 326 | 326 |
existing, ok := idTxn.Get(idVal) |
| 327 | 327 |
if !ok {
|
| ... | ... |
@@ -513,7 +518,19 @@ func (txn *Txn) DeleteAll(table, index string, args ...interface{}) (int, error)
|
| 513 | 513 |
} |
| 514 | 514 |
|
| 515 | 515 |
// FirstWatch is used to return the first matching object for |
| 516 |
-// the given constraints on the index along with the watch channel |
|
| 516 |
+// the given constraints on the index along with the watch channel. |
|
| 517 |
+// |
|
| 518 |
+// Note that all values read in the transaction form a consistent snapshot |
|
| 519 |
+// from the time when the transaction was created. |
|
| 520 |
+// |
|
| 521 |
+// The watch channel is closed when a subsequent write transaction |
|
| 522 |
+// has updated the result of the query. Since each read transaction |
|
| 523 |
+// operates on an isolated snapshot, a new read transaction must be |
|
| 524 |
+// started to observe the changes that have been made. |
|
| 525 |
+// |
|
| 526 |
+// If the value of index ends with "_prefix", FirstWatch will perform a prefix |
|
| 527 |
+// match instead of full match on the index. The registered indexer must implement |
|
| 528 |
+// PrefixIndexer, otherwise an error is returned. |
|
| 517 | 529 |
func (txn *Txn) FirstWatch(table, index string, args ...interface{}) (<-chan struct{}, interface{}, error) {
|
| 518 | 530 |
// Get the index value |
| 519 | 531 |
indexSchema, val, err := txn.getIndexValue(table, index, args...) |
| ... | ... |
@@ -541,7 +558,19 @@ func (txn *Txn) FirstWatch(table, index string, args ...interface{}) (<-chan str
|
| 541 | 541 |
} |
| 542 | 542 |
|
| 543 | 543 |
// LastWatch is used to return the last matching object for |
| 544 |
-// the given constraints on the index along with the watch channel |
|
| 544 |
+// the given constraints on the index along with the watch channel. |
|
| 545 |
+// |
|
| 546 |
+// Note that all values read in the transaction form a consistent snapshot |
|
| 547 |
+// from the time when the transaction was created. |
|
| 548 |
+// |
|
| 549 |
+// The watch channel is closed when a subsequent write transaction |
|
| 550 |
+// has updated the result of the query. Since each read transaction |
|
| 551 |
+// operates on an isolated snapshot, a new read transaction must be |
|
| 552 |
+// started to observe the changes that have been made. |
|
| 553 |
+// |
|
| 554 |
+// If the value of index ends with "_prefix", LastWatch will perform a prefix |
|
| 555 |
+// match instead of full match on the index. The registered indexer must implement |
|
| 556 |
+// PrefixIndexer, otherwise an error is returned. |
|
| 545 | 557 |
func (txn *Txn) LastWatch(table, index string, args ...interface{}) (<-chan struct{}, interface{}, error) {
|
| 546 | 558 |
// Get the index value |
| 547 | 559 |
indexSchema, val, err := txn.getIndexValue(table, index, args...) |
| ... | ... |
@@ -569,14 +598,20 @@ func (txn *Txn) LastWatch(table, index string, args ...interface{}) (<-chan stru
|
| 569 | 569 |
} |
| 570 | 570 |
|
| 571 | 571 |
// First is used to return the first matching object for |
| 572 |
-// the given constraints on the index |
|
| 572 |
+// the given constraints on the index. |
|
| 573 |
+// |
|
| 574 |
+// Note that all values read in the transaction form a consistent snapshot |
|
| 575 |
+// from the time when the transaction was created. |
|
| 573 | 576 |
func (txn *Txn) First(table, index string, args ...interface{}) (interface{}, error) {
|
| 574 | 577 |
_, val, err := txn.FirstWatch(table, index, args...) |
| 575 | 578 |
return val, err |
| 576 | 579 |
} |
| 577 | 580 |
|
| 578 | 581 |
// Last is used to return the last matching object for |
| 579 |
-// the given constraints on the index |
|
| 582 |
+// the given constraints on the index. |
|
| 583 |
+// |
|
| 584 |
+// Note that all values read in the transaction form a consistent snapshot |
|
| 585 |
+// from the time when the transaction was created. |
|
| 580 | 586 |
func (txn *Txn) Last(table, index string, args ...interface{}) (interface{}, error) {
|
| 581 | 587 |
_, val, err := txn.LastWatch(table, index, args...) |
| 582 | 588 |
return val, err |
| ... | ... |
@@ -589,6 +624,9 @@ func (txn *Txn) Last(table, index string, args ...interface{}) (interface{}, err
|
| 589 | 589 |
// null and fail to find a leaf node). This should only be used where the prefix |
| 590 | 590 |
// given is capable of matching indexed entries directly, which typically only |
| 591 | 591 |
// applies to a custom indexer. See the unit test for an example. |
| 592 |
+// |
|
| 593 |
+// Note that all values read in the transaction form a consistent snapshot |
|
| 594 |
+// from the time when the transaction was created. |
|
| 592 | 595 |
func (txn *Txn) LongestPrefix(table, index string, args ...interface{}) (interface{}, error) {
|
| 593 | 596 |
// Enforce that this only works on prefix indexes. |
| 594 | 597 |
if !strings.HasSuffix(index, "_prefix") {
|
| ... | ... |
@@ -725,6 +763,7 @@ func (txn *Txn) Get(table, index string, args ...interface{}) (ResultIterator, e
|
| 725 | 725 |
// The returned ResultIterator's Next() will return the next Previous value. |
| 726 | 726 |
// |
| 727 | 727 |
// See the documentation on Get for details on arguments. |
| 728 |
+// |
|
| 728 | 729 |
// See the documentation for ResultIterator to understand the behaviour of the |
| 729 | 730 |
// returned ResultIterator. |
| 730 | 731 |
func (txn *Txn) GetReverse(table, index string, args ...interface{}) (ResultIterator, error) {
|
| ... | ... |
@@ -751,6 +790,10 @@ func (txn *Txn) GetReverse(table, index string, args ...interface{}) (ResultIter
|
| 751 | 751 |
// iterator since the radix tree doesn't efficiently allow watching on lower |
| 752 | 752 |
// bound changes. The WatchCh returned will be nill and so will block forever. |
| 753 | 753 |
// |
| 754 |
+// If the value of index ends with "_prefix", LowerBound will perform a prefix match instead of |
|
| 755 |
+// a full match on the index. The registered index must implement PrefixIndexer, |
|
| 756 |
+// otherwise an error is returned. |
|
| 757 |
+// |
|
| 754 | 758 |
// See the documentation for ResultIterator to understand the behaviour of the |
| 755 | 759 |
// returned ResultIterator. |
| 756 | 760 |
func (txn *Txn) LowerBound(table, index string, args ...interface{}) (ResultIterator, error) {
|
| ... | ... |
@@ -1,3 +1,6 @@ |
| 1 |
+// Copyright (c) HashiCorp, Inc. |
|
| 2 |
+// SPDX-License-Identifier: MPL-2.0 |
|
| 3 |
+ |
|
| 1 | 4 |
package memdb |
| 2 | 5 |
|
| 3 | 6 |
import ( |
| ... | ... |
@@ -5,7 +8,8 @@ import ( |
| 5 | 5 |
"time" |
| 6 | 6 |
) |
| 7 | 7 |
|
| 8 |
-// WatchSet is a collection of watch channels. |
|
| 8 |
+// WatchSet is a collection of watch channels. The zero value is not usable. |
|
| 9 |
+// Use NewWatchSet to create a WatchSet. |
|
| 9 | 10 |
type WatchSet map[<-chan struct{}]struct{}
|
| 10 | 11 |
|
| 11 | 12 |
// NewWatchSet constructs a new watch set. |
| ... | ... |
@@ -31,7 +35,7 @@ func (w WatchSet) Add(watchCh <-chan struct{}) {
|
| 31 | 31 |
// not by much. |
| 32 | 32 |
// |
| 33 | 33 |
// This is useful if you want to track individual items up to some limit, after |
| 34 |
-// which you watch a higher-level channel (usually a channel from start start of |
|
| 34 |
+// which you watch a higher-level channel (usually a channel from start of |
|
| 35 | 35 |
// an iterator higher up in the radix tree) that will watch a superset of items. |
| 36 | 36 |
func (w WatchSet) AddWithLimit(softLimit int, watchCh <-chan struct{}, altCh <-chan struct{}) {
|
| 37 | 37 |
// This is safe for a nil WatchSet so we don't need to check that here. |
| ... | ... |
@@ -42,8 +46,9 @@ func (w WatchSet) AddWithLimit(softLimit int, watchCh <-chan struct{}, altCh <-c
|
| 42 | 42 |
} |
| 43 | 43 |
} |
| 44 | 44 |
|
| 45 |
-// Watch is used to wait for either the watch set to trigger or a timeout. |
|
| 46 |
-// Returns true on timeout. |
|
| 45 |
+// Watch blocks until one of the channels in the watch set is closed, or |
|
| 46 |
+// timeoutCh sends a value. |
|
| 47 |
+// Returns true if timeoutCh is what caused Watch to unblock. |
|
| 47 | 48 |
func (w WatchSet) Watch(timeoutCh <-chan time.Time) bool {
|
| 48 | 49 |
if w == nil {
|
| 49 | 50 |
return false |
| ... | ... |
@@ -64,9 +69,11 @@ func (w WatchSet) Watch(timeoutCh <-chan time.Time) bool {
|
| 64 | 64 |
return w.WatchCtx(ctx) == context.Canceled |
| 65 | 65 |
} |
| 66 | 66 |
|
| 67 |
-// WatchCtx is used to wait for either the watch set to trigger or for the |
|
| 68 |
-// context to be cancelled. Watch with a timeout channel can be mimicked by |
|
| 69 |
-// creating a context with a deadline. WatchCtx should be preferred over Watch. |
|
| 67 |
+// WatchCtx blocks until one of the channels in the watch set is closed, or |
|
| 68 |
+// ctx is done (cancelled or exceeds the deadline). WatchCtx returns an error |
|
| 69 |
+// if the ctx causes it to unblock, otherwise returns nil. |
|
| 70 |
+// |
|
| 71 |
+// WatchCtx should be preferred over Watch. |
|
| 70 | 72 |
func (w WatchSet) WatchCtx(ctx context.Context) error {
|
| 71 | 73 |
if w == nil {
|
| 72 | 74 |
return nil |
| ... | ... |
@@ -87,10 +94,14 @@ func (w WatchSet) WatchCtx(ctx context.Context) error {
|
| 87 | 87 |
|
| 88 | 88 |
// watchMany is used if there are many watchers. |
| 89 | 89 |
func (w WatchSet) watchMany(ctx context.Context) error {
|
| 90 |
+ // Cancel all watcher goroutines when return. |
|
| 91 |
+ watcherCtx, cancel := context.WithCancel(ctx) |
|
| 92 |
+ defer cancel() |
|
| 93 |
+ |
|
| 90 | 94 |
// Set up a goroutine for each watcher. |
| 91 | 95 |
triggerCh := make(chan struct{}, 1)
|
| 92 | 96 |
watcher := func(chunk []<-chan struct{}) {
|
| 93 |
- if err := watchFew(ctx, chunk); err == nil {
|
|
| 97 |
+ if err := watchFew(watcherCtx, chunk); err == nil {
|
|
| 94 | 98 |
select {
|
| 95 | 99 |
case triggerCh <- struct{}{}:
|
| 96 | 100 |
default: |
| ... | ... |
@@ -128,7 +139,7 @@ func (w WatchSet) watchMany(ctx context.Context) error {
|
| 128 | 128 |
} |
| 129 | 129 |
} |
| 130 | 130 |
|
| 131 |
-// WatchCh returns a channel that is used to wait for either the watch set to trigger |
|
| 131 |
+// WatchCh returns a channel that is used to wait for any channel of the watch set to trigger |
|
| 132 | 132 |
// or for the context to be cancelled. WatchCh creates a new goroutine each call, so |
| 133 | 133 |
// callers may need to cache the returned channel to avoid creating extra goroutines. |
| 134 | 134 |
func (w WatchSet) WatchCh(ctx context.Context) <-chan error {
|
| ... | ... |
@@ -686,8 +686,8 @@ github.com/hashicorp/go-immutable-radix |
| 686 | 686 |
# github.com/hashicorp/go-immutable-radix/v2 v2.1.0 |
| 687 | 687 |
## explicit; go 1.18 |
| 688 | 688 |
github.com/hashicorp/go-immutable-radix/v2 |
| 689 |
-# github.com/hashicorp/go-memdb v1.3.2 |
|
| 690 |
-## explicit; go 1.12 |
|
| 689 |
+# github.com/hashicorp/go-memdb v1.3.5 |
|
| 690 |
+## explicit; go 1.13 |
|
| 691 | 691 |
github.com/hashicorp/go-memdb |
| 692 | 692 |
# github.com/hashicorp/go-msgpack v0.5.5 |
| 693 | 693 |
## explicit |