Gets the body etc. out of a revCacheValue. If they aren't present already, the loader func will be called. This is synchronized so that the loader will only be called once even if multiple goroutines try to load at the same time.
(ctx context.Context, backingStore RevisionCacheBackingStore, includeDelta bool, loadBackup bool)
| 658 | // will be called. This is synchronized so that the loader will only be called once even if |
| 659 | // multiple goroutines try to load at the same time. |
| 660 | func (value *revCacheValue) load(ctx context.Context, backingStore RevisionCacheBackingStore, includeDelta bool, loadBackup bool) (docRev DocumentRevision, cacheHit bool, err error) { |
| 661 | |
| 662 | // Reading the delta from the revCacheValue requires holding the read lock, so it's managed outside asDocumentRevision, |
| 663 | // to reduce locking when includeDelta=false |
| 664 | var delta *RevisionDelta |
| 665 | var revid string |
| 666 | |
| 667 | // Attempt to read cached value. |
| 668 | value.lock.RLock() |
| 669 | if value.bodyBytes != nil || value.err != nil { |
| 670 | if includeDelta { |
| 671 | delta = value.delta |
| 672 | } |
| 673 | value.lock.RUnlock() |
| 674 | |
| 675 | docRev, err = value.asDocumentRevision(delta) |
| 676 | |
| 677 | return docRev, true, err |
| 678 | } |
| 679 | value.lock.RUnlock() |
| 680 | |
| 681 | value.lock.Lock() |
| 682 | defer value.lock.Unlock() |
| 683 | // Check if the value was loaded while we waited for the lock - if so, return. |
| 684 | if value.bodyBytes != nil || value.err != nil { |
| 685 | cacheHit = true |
| 686 | } else { |
| 687 | // we only want to set can evict if we are having to load the doc from the bucket into value, |
| 688 | // avoiding setting this value multiple times in the case other goroutines are loading the same value |
| 689 | defer func() { |
| 690 | value.canEvict.Store(true) // once done loading doc we can set the value to be ready for eviction |
| 691 | }() |
| 692 | |
| 693 | cacheHit = false |
| 694 | hlv := &HybridLogicalVector{} |
| 695 | if value.revID == "" { |
| 696 | hlvKey := IDandCV{DocID: value.id, Source: value.cv.SourceID, Version: value.cv.Value} |
| 697 | value.bodyBytes, value.history, value.channels, value.removed, value.attachments, value.deleted, value.expiry, revid, hlv, value.err = revCacheLoaderForCv(ctx, backingStore, hlvKey, loadBackup) |
| 698 | // based off the current value load we need to populate the revid key with what has been fetched from the bucket (for use of populating the opposite lookup map) |
| 699 | if revid != "" { |
| 700 | value.revID = revid |
| 701 | } |
| 702 | if hlv != nil { |
| 703 | value.hlvHistory = hlv.ToHistoryForHLV() |
| 704 | } |
| 705 | } else { |
| 706 | revKey := IDAndRev{DocID: value.id, RevID: value.revID} |
| 707 | value.bodyBytes, value.history, value.channels, value.removed, value.attachments, value.deleted, value.expiry, hlv, value.err = revCacheLoader(ctx, backingStore, revKey) |
| 708 | // based off the revision load we need to populate the hlv key with what has been fetched from the bucket (for use of populating the opposite lookup map) |
| 709 | if hlv != nil { |
| 710 | value.cv = *hlv.ExtractCurrentVersionFromHLV() |
| 711 | value.hlvHistory = hlv.ToHistoryForHLV() |
| 712 | } |
| 713 | } |
| 714 | } |
| 715 | |
| 716 | if includeDelta { |
| 717 | delta = value.delta |
no test coverage detected