go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/gae/service/datastore/multiarg.go (about) 1 // Copyright 2015 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package datastore 16 17 import ( 18 "fmt" 19 "reflect" 20 "sort" 21 "sync" 22 23 "go.chromium.org/luci/common/errors" 24 ) 25 26 type metaMultiArgConstraints int 27 28 const ( 29 // mmaReadWrite allows a metaMultiArg to operate on any type that can be 30 // both read and written to. 31 mmaReadWrite metaMultiArgConstraints = iota 32 // mmaKeysOnly implies mmaReadWrite, with the further statement that the only 33 // operation that will be performed against the arguments will be key 34 // extraction. 35 mmaKeysOnly = iota 36 // mmaWriteKeys indicates that the caller is only going to write key 37 // values. This enables the same inputs as mmaReadWrite, but also allows 38 // []*Key. 39 mmaWriteKeys = iota 40 ) 41 42 func (c metaMultiArgConstraints) allowSingleKey() bool { 43 return c == mmaKeysOnly 44 } 45 46 func (c metaMultiArgConstraints) keyOperationsOnly() bool { 47 return c >= mmaKeysOnly 48 } 49 50 type multiArgType struct { 51 getMGS func(slot reflect.Value) MetaGetterSetter 52 getPLS func(slot reflect.Value) PropertyLoadSaver 53 newElem func() reflect.Value 54 } 55 56 func (mat *multiArgType) getKey(kc KeyContext, slot reflect.Value) (*Key, error) { 57 return kc.NewKeyFromMeta(mat.getMGS(slot)) 58 } 59 60 func (mat *multiArgType) getPM(slot reflect.Value) (PropertyMap, error) { 61 return mat.getPLS(slot).Save(true) 62 } 63 64 func (mat *multiArgType) getMetaPM(slot reflect.Value) PropertyMap { 65 return mat.getMGS(slot).GetAllMeta() 66 } 67 68 func (mat *multiArgType) setPM(slot reflect.Value, pm PropertyMap) error { 69 return mat.getPLS(slot).Load(pm) 70 } 71 72 func (mat *multiArgType) setKey(slot reflect.Value, k *Key) bool { 73 return populateKeyMGS(mat.getMGS(slot), k) 74 } 75 76 // parseArg checks that et is of type S, *S, I, P or *P, for some 77 // struct type S, for some interface type I, or some non-interface non-pointer 78 // type P such that P or *P implements PropertyLoadSaver. 79 // 80 // If et is a chan type that implements PropertyLoadSaver, new elements will be 81 // allocated with a buffer of 0. 82 // 83 // If allowKey is true, et may additional be type *Key. Only MetaGetterSetter 84 // fields will be populated in the result (see keyMGS). 85 func parseArg(et reflect.Type, allowKeys bool) *multiArgType { 86 var mat multiArgType 87 88 if et == typeOfKey { 89 if !allowKeys { 90 return nil 91 } 92 93 mat.getMGS = func(slot reflect.Value) MetaGetterSetter { return &keyMGS{slot: slot} } 94 return &mat 95 } 96 97 // If we do identify a structCodec for this type, retain it so we don't 98 // resolve it multiple times. 99 var codec *structCodec 100 initCodec := func(t reflect.Type) *structCodec { 101 if codec == nil { 102 codec = getCodec(t) 103 } 104 return codec 105 } 106 107 // Fill in MetaGetterSetter functions. 108 switch { 109 case et.Implements(typeOfMetaGetterSetter): 110 // MGS 111 mat.getMGS = func(slot reflect.Value) MetaGetterSetter { return slot.Interface().(MetaGetterSetter) } 112 113 case reflect.PtrTo(et).Implements(typeOfMetaGetterSetter): 114 // *MGS 115 mat.getMGS = func(slot reflect.Value) MetaGetterSetter { return slot.Addr().Interface().(MetaGetterSetter) } 116 117 default: 118 switch et.Kind() { 119 case reflect.Interface: 120 // I 121 mat.getMGS = func(slot reflect.Value) MetaGetterSetter { return getMGS(slot.Elem().Interface()) } 122 123 case reflect.Ptr: 124 // *S 125 if et.Elem().Kind() != reflect.Struct { 126 // Not a struct pointer. 127 return nil 128 } 129 130 initCodec(et.Elem()) 131 mat.getMGS = func(slot reflect.Value) MetaGetterSetter { return &structPLS{slot.Elem(), codec, nil} } 132 133 case reflect.Struct: 134 // S 135 initCodec(et) 136 mat.getMGS = func(slot reflect.Value) MetaGetterSetter { return &structPLS{slot, codec, nil} } 137 138 default: 139 // Don't know how to get MGS for this type. 140 return nil 141 } 142 } 143 144 // Fill in PropertyLoadSaver functions. 145 switch { 146 case et.Implements(typeOfPropertyLoadSaver): 147 // PLS 148 mat.getPLS = func(slot reflect.Value) PropertyLoadSaver { return slot.Interface().(PropertyLoadSaver) } 149 150 case reflect.PtrTo(et).Implements(typeOfPropertyLoadSaver): 151 // *PLS 152 mat.getPLS = func(slot reflect.Value) PropertyLoadSaver { return slot.Addr().Interface().(PropertyLoadSaver) } 153 154 default: 155 switch et.Kind() { 156 case reflect.Interface: 157 // I 158 mat.getPLS = func(slot reflect.Value) PropertyLoadSaver { 159 obj := slot.Elem().Interface() 160 if pls, ok := obj.(PropertyLoadSaver); ok { 161 return pls 162 } 163 return GetPLS(obj) 164 } 165 166 case reflect.Ptr: 167 // *S 168 if et.Elem().Kind() != reflect.Struct { 169 // Not a struct pointer. 170 return nil 171 } 172 initCodec(et.Elem()) 173 mat.getPLS = func(slot reflect.Value) PropertyLoadSaver { return &structPLS{slot.Elem(), codec, nil} } 174 175 case reflect.Struct: 176 // S 177 initCodec(et) 178 mat.getPLS = func(slot reflect.Value) PropertyLoadSaver { return &structPLS{slot, codec, nil} } 179 180 default: 181 // Don't know how to get PLS for this type. 182 return nil 183 } 184 } 185 186 // Generate new element. 187 // 188 // If a map/chan type implements an interface, its pointer is also considered 189 // to implement that interface. 190 // 191 // In this case, we have special pointer-to-map/chan logic in multiArgTypePLS. 192 mat.newElem = func() reflect.Value { 193 return reflect.New(et).Elem() 194 } 195 196 switch et.Kind() { 197 case reflect.Map: 198 mat.newElem = func() reflect.Value { 199 return reflect.MakeMap(et) 200 } 201 202 case reflect.Chan: 203 mat.newElem = func() reflect.Value { 204 return reflect.MakeChan(et, 0) 205 } 206 207 case reflect.Ptr: 208 elem := et.Elem() 209 switch elem.Kind() { 210 case reflect.Map: 211 mat.newElem = func() reflect.Value { 212 ptr := reflect.New(elem) 213 ptr.Elem().Set(reflect.MakeMap(elem)) 214 return ptr 215 } 216 217 case reflect.Chan: 218 mat.newElem = func() reflect.Value { 219 ptr := reflect.New(elem) 220 ptr.Elem().Set(reflect.MakeChan(elem, 0)) 221 return ptr 222 } 223 224 default: 225 mat.newElem = func() reflect.Value { return reflect.New(et.Elem()) } 226 } 227 228 case reflect.Interface: 229 mat.newElem = nil 230 } 231 232 return &mat 233 } 234 235 // mustParseMultiArg checks that v has type []S, []*S, []I, []P or []*P, for 236 // some struct type S, for some interface type I, or some non-interface 237 // non-pointer type P such that P or *P implements PropertyLoadSaver. 238 func mustParseMultiArg(et reflect.Type) *multiArgType { 239 if et.Kind() != reflect.Slice { 240 panic(fmt.Errorf("invalid argument type: expected slice, got %s", et)) 241 } 242 return mustParseArg(et.Elem(), true) 243 } 244 245 func mustParseArg(et reflect.Type, sliceArg bool) *multiArgType { 246 if mat := parseArg(et, false); mat != nil { 247 return mat 248 } 249 panic(fmt.Errorf("invalid argument type: %s is not a PLS or pointer-to-struct", et)) 250 } 251 252 func isOKSingleType(t reflect.Type, allowKey bool) error { 253 switch { 254 case t == nil: 255 return errors.New("no type information") 256 case t.Implements(typeOfPropertyLoadSaver): 257 return nil 258 case !allowKey && t == typeOfKey: 259 return errors.New("not user datatype") 260 261 case t.Kind() != reflect.Ptr: 262 return errors.New("not a pointer") 263 case t.Elem().Kind() != reflect.Struct: 264 return errors.New("does not point to a struct") 265 266 default: 267 return nil 268 } 269 } 270 271 func isNilValue(t reflect.Type, v reflect.Value) bool { 272 k := t.Kind() 273 // `var v Interface = nil` and `var v *Struct = nil`. 274 if (k == reflect.Ptr || k == reflect.Interface) && v.IsNil() { 275 return true 276 } 277 // `var v Interface = (*Struct)nil`. 278 if k == reflect.Interface && v.Elem().IsNil() { 279 return true 280 } 281 return false 282 } 283 284 // keyMGS is a MetaGetterSetter that wraps a single key value/slot. It only 285 // implements operations on the "key" key. 286 // 287 // GetMeta will be implemented, returning the *Key for the "key" meta. 288 // 289 // If slot is addressable, SetMeta will allow it to be set to the supplied 290 // Value. 291 type keyMGS struct { 292 slot reflect.Value 293 } 294 295 func (mgs *keyMGS) GetAllMeta() PropertyMap { 296 return PropertyMap{"$key": MkPropertyNI(mgs.slot.Interface())} 297 } 298 299 func (mgs *keyMGS) GetMeta(key string) (any, bool) { 300 if key != "key" { 301 return nil, false 302 } 303 return mgs.slot.Interface(), true 304 } 305 306 func (mgs *keyMGS) SetMeta(key string, value any) bool { 307 if !(key == "key" && mgs.slot.CanAddr()) { 308 return false 309 } 310 mgs.slot.Set(reflect.ValueOf(value)) 311 return true 312 } 313 314 // metaMultiArgIndex is a two-dimensional index into a metaMultiArg. 315 type metaMultiArgIndex struct { 316 // elem is the index of the element in a metaMultiArg. 317 elem int 318 // slot is the index within the specified element. If the element is not a 319 // slice, slot will always be 0. 320 slot int 321 } 322 323 type metaMultiArgElement struct { 324 arg reflect.Value 325 mat *multiArgType 326 327 // size is -1 if this element is not a slice. 328 size int 329 // offset is the offset of the first element in the flattened space. 330 offset int 331 } 332 333 // length returns the number of elements in this metaMultiArgElement. 334 // 335 // If it represents a slice, the number of elements will be the length of that 336 // slice. If it represents a single value, the length will be 1. 337 func (e *metaMultiArgElement) length() int { 338 if e.size >= 0 { 339 return e.size 340 } 341 return 1 342 } 343 344 type metaMultiArg struct { 345 // elems is the set of metaMultiArgElement entries, each of which represents 346 // either a single value or a slice of single values. 347 elems []metaMultiArgElement 348 keysOnly bool 349 350 // count is the total number of elements, flattening slices. 351 count int 352 // flat, if true, means that this metaMultiArg consists entirely of single 353 // elements (no slices). This is used as a lookup optimization to avoid binary 354 // index search. 355 flat bool 356 } 357 358 // makeMetaMultiArg returns a metaMultiArg for the supplied args. 359 // 360 // If an arg is a slice, a slice metaMultiArg will be returned, and errors for 361 // that slice will be written into a positional MultiError if they occur. 362 // 363 // If keysOnly is true, the caller is instructing metaMultiArg to only extract 364 // the datastore *Key from args. *Key entries will be permitted, but the caller 365 // may not write to them (since keys are read-only structs). 366 func makeMetaMultiArg(args []any, c metaMultiArgConstraints) (*metaMultiArg, error) { 367 mma := metaMultiArg{ 368 elems: make([]metaMultiArgElement, len(args)), 369 keysOnly: c.keyOperationsOnly(), 370 flat: true, 371 } 372 373 lme := errors.NewLazyMultiError(len(args)) 374 for i, arg := range args { 375 if arg == nil { 376 lme.Assign(i, errors.New("cannot use nil as single argument")) 377 continue 378 } 379 380 v := reflect.ValueOf(arg) 381 vt := v.Type() 382 383 // The arg can be a "typed nil", they are not allowed either. 384 if isNilValue(vt, v) { 385 lme.Assign(i, errors.New("cannot use typed nil as single argument")) 386 continue 387 } 388 389 // Try and treat the argument as a single-value first. This allows slices 390 // that implement PropertyLoadSaver to be properly treated as a single 391 // element. 392 var ( 393 mat *multiArgType 394 err error 395 isSlice = false 396 ) 397 if mat = parseArg(vt, c.allowSingleKey()); mat == nil { 398 // If this is a slice, treat it as a slice of arg candidates. 399 // 400 // If only keys are being read/written, we allow a []*Key to be accepted 401 // here, since slices are addressable (write). 402 if v.Kind() == reflect.Slice { 403 isSlice = true 404 mma.flat = false 405 mat = parseArg(vt.Elem(), c.keyOperationsOnly()) 406 } 407 } else { 408 // Single types need to be able to be assigned to. 409 // 410 // We only allow *Key here when the keys cannot be written to, since *Key 411 // should not be modified in-place, as they are immutable. 412 err = isOKSingleType(vt, c.allowSingleKey()) 413 } 414 if mat == nil && err == nil { 415 err = errors.New("not a PLS, pointer-to-struct, or slice thereof") 416 } 417 if err != nil { 418 lme.Assign(i, fmt.Errorf("invalid input type (%T): %s", arg, err)) 419 continue 420 } 421 422 // The type checks out, but there may be nils sneaking inside the slice. 423 if isSlice { 424 for sliceIdx := 0; sliceIdx < v.Len(); sliceIdx++ { 425 e := v.Index(sliceIdx) 426 if isNilValue(e.Type(), e) { 427 err = fmt.Errorf("invalid input slice: has nil at index %d", sliceIdx) 428 break 429 } 430 } 431 if err != nil { 432 lme.Assign(i, err) 433 continue 434 } 435 } 436 437 elem := &mma.elems[i] 438 *elem = metaMultiArgElement{ 439 arg: v, 440 mat: mat, 441 offset: mma.count, 442 } 443 if isSlice { 444 l := v.Len() 445 mma.count += l 446 elem.size = l 447 } else { 448 mma.count++ 449 elem.size = -1 450 } 451 } 452 if err := lme.Get(); err != nil { 453 return nil, err 454 } 455 456 return &mma, nil 457 } 458 459 func (mma *metaMultiArg) index(idx int) (mmaIdx metaMultiArgIndex) { 460 if mma.flat { 461 mmaIdx.elem = idx 462 return 463 } 464 465 mmaIdx.elem = sort.Search(len(mma.elems), func(i int) bool { return mma.elems[i].offset > idx }) - 1 466 467 // Get the current slot value. 468 mmaIdx.slot = idx - mma.elems[mmaIdx.elem].offset 469 return 470 } 471 472 // get returns the element type and value at flattened index idx. 473 func (mma *metaMultiArg) get(idx metaMultiArgIndex) (*multiArgType, reflect.Value) { 474 // Get the current slot value. 475 elem := &mma.elems[idx.elem] 476 slot := elem.arg 477 if elem.size >= 0 { 478 // slot is a slice type, get its member. 479 slot = slot.Index(idx.slot) 480 } 481 482 return elem.mat, slot 483 } 484 485 // getKeysPMs returns the keys and PropertyMap for the supplied argument items. 486 func (mma *metaMultiArg) getKeysPMs(kc KeyContext, meta bool) ([]*Key, []PropertyMap, *errorTracker) { 487 et := newErrorTracker(mma) 488 489 // Determine our flattened keys and property maps. 490 retKey := make([]*Key, mma.count) 491 var retPM []PropertyMap 492 if !mma.keysOnly { 493 retPM = make([]PropertyMap, mma.count) 494 } 495 496 var index metaMultiArgIndex 497 for i := 0; i < mma.count; i++ { 498 // If we're past the end of the element, move onto the next. 499 for index.slot >= mma.elems[index.elem].length() { 500 index.elem++ 501 index.slot = 0 502 } 503 504 mat, slot := mma.get(index) 505 key, err := mat.getKey(kc, slot) 506 if err != nil { 507 et.trackError(index, err) 508 index.slot++ 509 continue 510 } 511 retKey[i] = key 512 513 if !mma.keysOnly { 514 var pm PropertyMap 515 if meta { 516 pm = mat.getMetaPM(slot) 517 } else { 518 var err error 519 if pm, err = mat.getPM(slot); err != nil { 520 et.trackError(index, err) 521 index.slot++ 522 continue 523 } 524 } 525 retPM[i] = pm 526 } 527 528 index.slot++ 529 } 530 return retKey, retPM, et 531 } 532 533 type errorTracker struct { 534 sync.Mutex 535 536 elemErrors errors.MultiError 537 mma *metaMultiArg 538 } 539 540 func newErrorTracker(mma *metaMultiArg) *errorTracker { 541 return &errorTracker{ 542 mma: mma, 543 } 544 } 545 546 func (et *errorTracker) trackError(index metaMultiArgIndex, err error) { 547 if err == nil { 548 return 549 } 550 551 et.Lock() 552 defer et.Unlock() 553 et.trackErrorLocked(index, err) 554 } 555 556 func (et *errorTracker) trackErrorLocked(index metaMultiArgIndex, err error) { 557 if err == nil { 558 return 559 } 560 561 if et.elemErrors == nil { 562 et.elemErrors = make(errors.MultiError, len(et.mma.elems)) 563 } 564 565 // If this is a single element, assign the error directly. 566 elem := &et.mma.elems[index.elem] 567 if elem.size < 0 { 568 et.elemErrors[index.elem] = err 569 } else { 570 // This is a slice element. Use a slice-sized MultiError for its element 571 // error slot, then add this error to the inner MultiError's slot index. 572 serr, ok := et.elemErrors[index.elem].(errors.MultiError) 573 if !ok { 574 serr = make(errors.MultiError, elem.size) 575 et.elemErrors[index.elem] = serr 576 } 577 serr[index.slot] = err 578 } 579 } 580 581 func (et *errorTracker) error() error { 582 if et.elemErrors != nil { 583 return et.elemErrors 584 } 585 return nil 586 } 587 588 type boolTracker struct { 589 *errorTracker 590 591 res ExistsResult 592 } 593 594 func newBoolTracker(mma *metaMultiArg, et *errorTracker) *boolTracker { 595 bt := boolTracker{ 596 errorTracker: et, 597 } 598 599 sizes := make([]int, len(mma.elems)) 600 for i, e := range mma.elems { 601 if e.size < 0 { 602 sizes[i] = 1 603 } else { 604 sizes[i] = e.size 605 } 606 } 607 bt.res.init(sizes...) 608 return &bt 609 } 610 611 func (bt *boolTracker) trackExistsResult(index metaMultiArgIndex, err error) { 612 bt.Lock() 613 defer bt.Unlock() 614 615 switch err { 616 case nil: 617 bt.res.set(index.elem, index.slot) 618 619 case ErrNoSuchEntity: 620 break 621 622 default: 623 // Pass through to track as MultiError. 624 bt.trackErrorLocked(index, err) 625 } 626 } 627 628 func (bt *boolTracker) result() *ExistsResult { 629 bt.res.updateSlices() 630 return &bt.res 631 }