github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/dataloaders/formationconstraintloader_gen.go (about) 1 // Code generated by github.com/vektah/dataloaden, DO NOT EDIT. 2 3 package dataloader 4 5 import ( 6 "sync" 7 "time" 8 9 "github.com/kyma-incubator/compass/components/director/pkg/graphql" 10 ) 11 12 // FormationConstraintLoaderConfig captures the config to create a new FormationConstraintLoader 13 type FormationConstraintLoaderConfig struct { 14 // Fetch is a method that provides the data for the loader 15 Fetch func(keys []ParamFormationConstraint) ([][]*graphql.FormationConstraint, []error) 16 17 // Wait is how long wait before sending a batch 18 Wait time.Duration 19 20 // MaxBatch will limit the maximum number of keys to send in one batch, 0 = not limit 21 MaxBatch int 22 } 23 24 // NewFormationConstraintLoader creates a new FormationConstraintLoader given a fetch, wait, and maxBatch 25 func NewFormationConstraintLoader(config FormationConstraintLoaderConfig) *FormationConstraintLoader { 26 return &FormationConstraintLoader{ 27 fetch: config.Fetch, 28 wait: config.Wait, 29 maxBatch: config.MaxBatch, 30 } 31 } 32 33 // FormationConstraintLoader batches and caches requests 34 type FormationConstraintLoader struct { 35 // this method provides the data for the loader 36 fetch func(keys []ParamFormationConstraint) ([][]*graphql.FormationConstraint, []error) 37 38 // how long to done before sending a batch 39 wait time.Duration 40 41 // this will limit the maximum number of keys to send in one batch, 0 = no limit 42 maxBatch int 43 44 // INTERNAL 45 46 // lazily created cache 47 cache map[ParamFormationConstraint][]*graphql.FormationConstraint 48 49 // the current batch. keys will continue to be collected until timeout is hit, 50 // then everything will be sent to the fetch method and out to the listeners 51 batch *formationConstraintLoaderBatch 52 53 // mutex to prevent races 54 mu sync.Mutex 55 } 56 57 type formationConstraintLoaderBatch struct { 58 keys []ParamFormationConstraint 59 data [][]*graphql.FormationConstraint 60 error []error 61 closing bool 62 done chan struct{} 63 } 64 65 // Load a FormationConstraint by key, batching and caching will be applied automatically 66 func (l *FormationConstraintLoader) Load(key ParamFormationConstraint) ([]*graphql.FormationConstraint, error) { 67 return l.LoadThunk(key)() 68 } 69 70 // LoadThunk returns a function that when called will block waiting for a FormationConstraint. 71 // This method should be used if you want one goroutine to make requests to many 72 // different data loaders without blocking until the thunk is called. 73 func (l *FormationConstraintLoader) LoadThunk(key ParamFormationConstraint) func() ([]*graphql.FormationConstraint, error) { 74 l.mu.Lock() 75 if it, ok := l.cache[key]; ok { 76 l.mu.Unlock() 77 return func() ([]*graphql.FormationConstraint, error) { 78 return it, nil 79 } 80 } 81 if l.batch == nil { 82 l.batch = &formationConstraintLoaderBatch{done: make(chan struct{})} 83 } 84 batch := l.batch 85 pos := batch.keyIndex(l, key) 86 l.mu.Unlock() 87 88 return func() ([]*graphql.FormationConstraint, error) { 89 <-batch.done 90 91 var data []*graphql.FormationConstraint 92 if pos < len(batch.data) { 93 data = batch.data[pos] 94 } 95 96 var err error 97 // its convenient to be able to return a single error for everything 98 if len(batch.error) == 1 { 99 err = batch.error[0] 100 } else if batch.error != nil { 101 err = batch.error[pos] 102 } 103 104 if err == nil { 105 l.mu.Lock() 106 l.unsafeSet(key, data) 107 l.mu.Unlock() 108 } 109 110 return data, err 111 } 112 } 113 114 // LoadAll fetches many keys at once. It will be broken into appropriate sized 115 // sub batches depending on how the loader is configured 116 func (l *FormationConstraintLoader) LoadAll(keys []ParamFormationConstraint) ([][]*graphql.FormationConstraint, []error) { 117 results := make([]func() ([]*graphql.FormationConstraint, error), len(keys)) 118 119 for i, key := range keys { 120 results[i] = l.LoadThunk(key) 121 } 122 123 formationConstraints := make([][]*graphql.FormationConstraint, len(keys)) 124 errors := make([]error, len(keys)) 125 for i, thunk := range results { 126 formationConstraints[i], errors[i] = thunk() 127 } 128 return formationConstraints, errors 129 } 130 131 // LoadAllThunk returns a function that when called will block waiting for a FormationConstraints. 132 // This method should be used if you want one goroutine to make requests to many 133 // different data loaders without blocking until the thunk is called. 134 func (l *FormationConstraintLoader) LoadAllThunk(keys []ParamFormationConstraint) func() ([][]*graphql.FormationConstraint, []error) { 135 results := make([]func() ([]*graphql.FormationConstraint, error), len(keys)) 136 for i, key := range keys { 137 results[i] = l.LoadThunk(key) 138 } 139 return func() ([][]*graphql.FormationConstraint, []error) { 140 formationConstraints := make([][]*graphql.FormationConstraint, len(keys)) 141 errors := make([]error, len(keys)) 142 for i, thunk := range results { 143 formationConstraints[i], errors[i] = thunk() 144 } 145 return formationConstraints, errors 146 } 147 } 148 149 // Prime the cache with the provided key and value. If the key already exists, no change is made 150 // and false is returned. 151 // (To forcefully prime the cache, clear the key first with loader.clear(key).prime(key, value).) 152 func (l *FormationConstraintLoader) Prime(key ParamFormationConstraint, value []*graphql.FormationConstraint) bool { 153 l.mu.Lock() 154 var found bool 155 if _, found = l.cache[key]; !found { 156 // make a copy when writing to the cache, its easy to pass a pointer in from a loop var 157 // and end up with the whole cache pointing to the same value. 158 cpy := make([]*graphql.FormationConstraint, len(value)) 159 copy(cpy, value) 160 l.unsafeSet(key, cpy) 161 } 162 l.mu.Unlock() 163 return !found 164 } 165 166 // Clear the value at key from the cache, if it exists 167 func (l *FormationConstraintLoader) Clear(key ParamFormationConstraint) { 168 l.mu.Lock() 169 delete(l.cache, key) 170 l.mu.Unlock() 171 } 172 173 func (l *FormationConstraintLoader) unsafeSet(key ParamFormationConstraint, value []*graphql.FormationConstraint) { 174 if l.cache == nil { 175 l.cache = map[ParamFormationConstraint][]*graphql.FormationConstraint{} 176 } 177 l.cache[key] = value 178 } 179 180 // keyIndex will return the location of the key in the batch, if its not found 181 // it will add the key to the batch 182 func (b *formationConstraintLoaderBatch) keyIndex(l *FormationConstraintLoader, key ParamFormationConstraint) int { 183 for i, existingKey := range b.keys { 184 if key == existingKey { 185 return i 186 } 187 } 188 189 pos := len(b.keys) 190 b.keys = append(b.keys, key) 191 if pos == 0 { 192 go b.startTimer(l) 193 } 194 195 if l.maxBatch != 0 && pos >= l.maxBatch-1 { 196 if !b.closing { 197 b.closing = true 198 l.batch = nil 199 go b.end(l) 200 } 201 } 202 203 return pos 204 } 205 206 func (b *formationConstraintLoaderBatch) startTimer(l *FormationConstraintLoader) { 207 time.Sleep(l.wait) 208 l.mu.Lock() 209 210 // we must have hit a batch limit and are already finalizing this batch 211 if b.closing { 212 l.mu.Unlock() 213 return 214 } 215 216 l.batch = nil 217 l.mu.Unlock() 218 219 b.end(l) 220 } 221 222 func (b *formationConstraintLoaderBatch) end(l *FormationConstraintLoader) { 223 b.data, b.error = l.fetch(b.keys) 224 close(b.done) 225 }