github.com/prebid/prebid-server/v2@v2.18.0/usersync/ejector.go (about) 1 package usersync 2 3 import ( 4 "errors" 5 "time" 6 ) 7 8 type Ejector interface { 9 Choose(uids map[string]UIDEntry) (string, error) 10 } 11 12 type OldestEjector struct{} 13 14 type PriorityBidderEjector struct { 15 PriorityGroups [][]string 16 SyncersByBidder map[string]Syncer 17 IsSyncerPriority bool 18 TieEjector Ejector 19 } 20 21 // Choose method for oldest ejector will return the oldest uid 22 func (o *OldestEjector) Choose(uids map[string]UIDEntry) (string, error) { 23 var oldestElement string 24 var oldestDate time.Time = time.Unix(1<<63-62135596801, 999999999) // Max value for time 25 26 for key, value := range uids { 27 if value.Expires.Before(oldestDate) { 28 oldestElement = key 29 oldestDate = value.Expires 30 } 31 } 32 return oldestElement, nil 33 } 34 35 // Choose method for priority ejector will return the oldest lowest priority element 36 func (p *PriorityBidderEjector) Choose(uids map[string]UIDEntry) (string, error) { 37 nonPriorityUids := getNonPriorityUids(uids, p.PriorityGroups, p.SyncersByBidder) 38 if err := p.checkSyncerPriority(nonPriorityUids); err != nil { 39 return "", err 40 } 41 42 if len(nonPriorityUids) > 0 { 43 return p.TieEjector.Choose(nonPriorityUids) 44 } 45 46 lowestPriorityGroup := p.PriorityGroups[len(p.PriorityGroups)-1] 47 if len(lowestPriorityGroup) == 1 { 48 uidToDelete := lowestPriorityGroup[0] 49 p.PriorityGroups = removeElementFromPriorityGroup(p.PriorityGroups, uidToDelete) 50 return uidToDelete, nil 51 } 52 53 lowestPriorityUids := getPriorityUids(lowestPriorityGroup, uids, p.SyncersByBidder) 54 uidToDelete, err := p.TieEjector.Choose(lowestPriorityUids) 55 if err != nil { 56 return "", err 57 } 58 p.PriorityGroups = removeElementFromPriorityGroup(p.PriorityGroups, uidToDelete) 59 return uidToDelete, nil 60 } 61 62 // updatePriorityGroup will remove the selected element from the priority groups, and will remove the entire priority group if it's empty 63 func removeElementFromPriorityGroup(priorityGroups [][]string, oldestElement string) [][]string { 64 lowestPriorityGroup := priorityGroups[len(priorityGroups)-1] 65 if len(lowestPriorityGroup) <= 1 { 66 return priorityGroups[:len(priorityGroups)-1] 67 } 68 69 for index, elem := range lowestPriorityGroup { 70 if elem == oldestElement { 71 updatedPriorityGroup := append(lowestPriorityGroup[:index], lowestPriorityGroup[index+1:]...) 72 priorityGroups[len(priorityGroups)-1] = updatedPriorityGroup 73 return priorityGroups 74 } 75 } 76 return priorityGroups 77 } 78 79 func getNonPriorityUids(uids map[string]UIDEntry, priorityGroups [][]string, syncersByBidder map[string]Syncer) map[string]UIDEntry { 80 // If no priority groups, then all keys in uids are non-priority 81 if len(priorityGroups) == 0 { 82 return uids 83 } 84 85 // Create map of keys that are a priority 86 isPriority := make(map[string]bool) 87 for _, group := range priorityGroups { 88 for _, bidder := range group { 89 if bidderSyncer, ok := syncersByBidder[bidder]; ok { 90 isPriority[bidderSyncer.Key()] = true 91 } 92 } 93 } 94 95 // Create a map for non-priority uids 96 nonPriorityUIDs := make(map[string]UIDEntry) 97 98 // Loop over uids and populate the nonPriorityUIDs map with non-priority keys 99 for key, value := range uids { 100 if _, found := isPriority[key]; !found { 101 nonPriorityUIDs[key] = value 102 } 103 } 104 105 return nonPriorityUIDs 106 } 107 108 func getPriorityUids(lowestPriorityGroup []string, uids map[string]UIDEntry, syncersByBidder map[string]Syncer) map[string]UIDEntry { 109 lowestPriorityUIDs := make(map[string]UIDEntry) 110 111 // Loop over lowestPriorityGroup and populate the lowestPriorityUIDs map 112 for _, bidder := range lowestPriorityGroup { 113 if bidderSyncer, ok := syncersByBidder[bidder]; ok { 114 if uidEntry, exists := uids[bidderSyncer.Key()]; exists { 115 lowestPriorityUIDs[bidderSyncer.Key()] = uidEntry 116 } 117 } 118 } 119 return lowestPriorityUIDs 120 } 121 122 func (p *PriorityBidderEjector) checkSyncerPriority(nonPriorityUids map[string]UIDEntry) error { 123 if len(nonPriorityUids) == 1 && !p.IsSyncerPriority && len(p.PriorityGroups) > 0 { 124 return errors.New("syncer key is not a priority, and there are only priority elements left") 125 } 126 return nil 127 }