Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / mod@v0.3.0 / sumdb / storage / mem.go
1 // Copyright 2019 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package storage
6
7 import (
8         "context"
9         "errors"
10         "math/rand"
11         "sync"
12 )
13
14 // Mem is an in-memory implementation of Storage.
15 // It is meant for tests and does not store any data to persistent storage.
16 //
17 // The zero value is an empty Mem ready for use.
18 type Mem struct {
19         mu    sync.RWMutex
20         table map[string]string
21 }
22
23 // A memTx is a transaction in a Mem.
24 type memTx struct {
25         m      *Mem
26         writes []Write
27 }
28
29 // errRetry is an internal sentinel indicating that the transaction should be retried.
30 // It is never returned to the caller.
31 var errRetry = errors.New("retry")
32
33 // ReadOnly runs f in a read-only transaction.
34 func (m *Mem) ReadOnly(ctx context.Context, f func(context.Context, Transaction) error) error {
35         tx := &memTx{m: m}
36         for {
37                 err := func() error {
38                         m.mu.Lock()
39                         defer m.mu.Unlock()
40
41                         if err := f(ctx, tx); err != nil {
42                                 return err
43                         }
44                         // Spurious retry with 10% probability.
45                         if rand.Intn(10) == 0 {
46                                 return errRetry
47                         }
48                         return nil
49                 }()
50                 if err != errRetry {
51                         return err
52                 }
53         }
54 }
55
56 // ReadWrite runs f in a read-write transaction.
57 func (m *Mem) ReadWrite(ctx context.Context, f func(context.Context, Transaction) error) error {
58         tx := &memTx{m: m}
59         for {
60                 err := func() error {
61                         m.mu.Lock()
62                         defer m.mu.Unlock()
63
64                         tx.writes = []Write{}
65                         if err := f(ctx, tx); err != nil {
66                                 return err
67                         }
68                         // Spurious retry with 10% probability.
69                         if rand.Intn(10) == 0 {
70                                 return errRetry
71                         }
72                         if m.table == nil {
73                                 m.table = make(map[string]string)
74                         }
75                         for _, w := range tx.writes {
76                                 if w.Value == "" {
77                                         delete(m.table, w.Key)
78                                 } else {
79                                         m.table[w.Key] = w.Value
80                                 }
81                         }
82                         return nil
83                 }()
84                 if err != errRetry {
85                         return err
86                 }
87         }
88 }
89
90 // ReadValues returns the values associated with the given keys.
91 func (tx *memTx) ReadValues(ctx context.Context, keys []string) ([]string, error) {
92         vals := make([]string, len(keys))
93         for i, key := range keys {
94                 vals[i] = tx.m.table[key]
95         }
96         return vals, nil
97 }
98
99 // ReadValue returns the value associated with the single key.
100 func (tx *memTx) ReadValue(ctx context.Context, key string) (string, error) {
101         return tx.m.table[key], nil
102 }
103
104 // BufferWrites buffers a list of writes to be applied
105 // to the table when the transaction commits.
106 // The changes are not visible to reads within the transaction.
107 // The map argument is not used after the call returns.
108 func (tx *memTx) BufferWrites(list []Write) error {
109         if tx.writes == nil {
110                 panic("BufferWrite on read-only transaction")
111         }
112         tx.writes = append(tx.writes, list...)
113         return nil
114 }