github.com/rigado/snapd@v2.42.5-go-mod+incompatible/asserts/membackstore.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2016 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package asserts 21 22 import ( 23 "errors" 24 "sync" 25 ) 26 27 type memoryBackstore struct { 28 top memBSBranch 29 mu sync.RWMutex 30 } 31 32 type memBSNode interface { 33 put(assertType *AssertionType, key []string, assert Assertion) error 34 get(key []string, maxFormat int) (Assertion, error) 35 search(hint []string, found func(Assertion), maxFormat int) 36 } 37 38 type memBSBranch map[string]memBSNode 39 40 type memBSLeaf map[string]map[int]Assertion 41 42 func (br memBSBranch) put(assertType *AssertionType, key []string, assert Assertion) error { 43 key0 := key[0] 44 down := br[key0] 45 if down == nil { 46 if len(key) > 2 { 47 down = make(memBSBranch) 48 } else { 49 down = make(memBSLeaf) 50 } 51 br[key0] = down 52 } 53 return down.put(assertType, key[1:], assert) 54 } 55 56 func (leaf memBSLeaf) cur(key0 string, maxFormat int) (a Assertion) { 57 for formatnum, a1 := range leaf[key0] { 58 if formatnum <= maxFormat { 59 if a == nil || a1.Revision() > a.Revision() { 60 a = a1 61 } 62 } 63 } 64 return a 65 } 66 67 func (leaf memBSLeaf) put(assertType *AssertionType, key []string, assert Assertion) error { 68 key0 := key[0] 69 cur := leaf.cur(key0, assertType.MaxSupportedFormat()) 70 if cur != nil { 71 rev := assert.Revision() 72 curRev := cur.Revision() 73 if curRev >= rev { 74 return &RevisionError{Current: curRev, Used: rev} 75 } 76 } 77 if _, ok := leaf[key0]; !ok { 78 leaf[key0] = make(map[int]Assertion) 79 } 80 leaf[key0][assert.Format()] = assert 81 return nil 82 } 83 84 // errNotFound is used internally by backends, it is converted to the richer 85 // NotFoundError only at their public interface boundary 86 var errNotFound = errors.New("assertion not found") 87 88 func (br memBSBranch) get(key []string, maxFormat int) (Assertion, error) { 89 key0 := key[0] 90 down := br[key0] 91 if down == nil { 92 return nil, errNotFound 93 } 94 return down.get(key[1:], maxFormat) 95 } 96 97 func (leaf memBSLeaf) get(key []string, maxFormat int) (Assertion, error) { 98 key0 := key[0] 99 cur := leaf.cur(key0, maxFormat) 100 if cur == nil { 101 return nil, errNotFound 102 } 103 return cur, nil 104 } 105 106 func (br memBSBranch) search(hint []string, found func(Assertion), maxFormat int) { 107 hint0 := hint[0] 108 if hint0 == "" { 109 for _, down := range br { 110 down.search(hint[1:], found, maxFormat) 111 } 112 return 113 } 114 down := br[hint0] 115 if down != nil { 116 down.search(hint[1:], found, maxFormat) 117 } 118 return 119 } 120 121 func (leaf memBSLeaf) search(hint []string, found func(Assertion), maxFormat int) { 122 hint0 := hint[0] 123 if hint0 == "" { 124 for key := range leaf { 125 cand := leaf.cur(key, maxFormat) 126 if cand != nil { 127 found(cand) 128 } 129 } 130 return 131 } 132 133 cur := leaf.cur(hint0, maxFormat) 134 if cur != nil { 135 found(cur) 136 } 137 } 138 139 // NewMemoryBackstore creates a memory backed assertions backstore. 140 func NewMemoryBackstore() Backstore { 141 return &memoryBackstore{ 142 top: make(memBSBranch), 143 } 144 } 145 146 func (mbs *memoryBackstore) Put(assertType *AssertionType, assert Assertion) error { 147 mbs.mu.Lock() 148 defer mbs.mu.Unlock() 149 150 internalKey := make([]string, 1, 1+len(assertType.PrimaryKey)) 151 internalKey[0] = assertType.Name 152 internalKey = append(internalKey, assert.Ref().PrimaryKey...) 153 154 err := mbs.top.put(assertType, internalKey, assert) 155 return err 156 } 157 158 func (mbs *memoryBackstore) Get(assertType *AssertionType, key []string, maxFormat int) (Assertion, error) { 159 mbs.mu.RLock() 160 defer mbs.mu.RUnlock() 161 162 internalKey := make([]string, 1+len(assertType.PrimaryKey)) 163 internalKey[0] = assertType.Name 164 copy(internalKey[1:], key) 165 166 a, err := mbs.top.get(internalKey, maxFormat) 167 if err == errNotFound { 168 return nil, &NotFoundError{Type: assertType} 169 } 170 return a, err 171 } 172 173 func (mbs *memoryBackstore) Search(assertType *AssertionType, headers map[string]string, foundCb func(Assertion), maxFormat int) error { 174 mbs.mu.RLock() 175 defer mbs.mu.RUnlock() 176 177 hint := make([]string, 1+len(assertType.PrimaryKey)) 178 hint[0] = assertType.Name 179 for i, name := range assertType.PrimaryKey { 180 hint[1+i] = headers[name] 181 } 182 183 candCb := func(a Assertion) { 184 if searchMatch(a, headers) { 185 foundCb(a) 186 } 187 } 188 189 mbs.top.search(hint, candCb, maxFormat) 190 return nil 191 }