+ while (num_elements_to_evict) {
+ /*
+ * LEAKS: reap the oldest element within the record with the lowest refs.
+ * CORRUPTION: reap the oldest element overall and drop its reference on the record
+ */
+
+ if (btlog->caller_will_remove_entries_for_element) {
+ uint32_t max_refs_threshold = UINT32_MAX;
+ btlog_recordindex_t precindex = 0, prev_evictindex = 0, evict_index = 0;
+
+ prev_evictindex = evict_index = btlog->head;
+ precindex = recindex = btlog->head;
+
+ while (recindex != BTLOG_RECORDINDEX_NONE) {
+ record = lookup_btrecord(btlog, recindex);
+
+ if (btlog->activerecord == recindex || record->ref_count > max_refs_threshold) {
+ /* skip this record */
+ } else {
+ prev_evictindex = precindex;
+ evict_index = recindex;
+ max_refs_threshold = record->ref_count;
+ }
+
+ if (record->next != BTLOG_RECORDINDEX_NONE) {
+ precindex = recindex;
+ }
+
+ recindex = record->next;
+ }
+
+ recindex = evict_index;
+ assert(recindex != BTLOG_RECORDINDEX_NONE);
+ record = lookup_btrecord(btlog, recindex);
+
+ recelem = TAILQ_LAST(&record->element_record_queue, _element_record_queue);
+ } else {
+ recelem = TAILQ_LAST(btlog->elem_linkage_un.element_hash_queue, _element_hash_queue);
+ recindex = recelem->recindex;
+ record = lookup_btrecord(btlog, recindex);
+ }
+
+ /*
+ * Here we have the element to drop (recelem), its record and the record index.
+ */
+
+ while (recelem && num_elements_to_evict) {
+ TAILQ_REMOVE(&record->element_record_queue, recelem, element_record_link);
+
+ if (btlog->caller_will_remove_entries_for_element) {
+ btlog_element_t *prev_hashelem = NULL, *hashelem = NULL;
+ uint32_t hashidx = 0;
+
+ hashidx = calculate_hashidx_for_element(~recelem->elem, btlog);
+
+ prev_hashelem = hashelem = btlog->elem_linkage_un.elem_recindex_hashtbl[hashidx];
+ while (hashelem != NULL) {
+ if (hashelem == recelem) {
+ break;
+ } else {
+ prev_hashelem = hashelem;
+ hashelem = TAILQ_NEXT(hashelem, element_hash_link);
+ }
+ }
+
+ if (hashelem == NULL) {
+ panic("BTLog: Missing hashelem for element list of record 0x%lx\n", (uintptr_t) record);
+ }
+
+ if (prev_hashelem != hashelem) {
+ TAILQ_NEXT(prev_hashelem, element_hash_link) = TAILQ_NEXT(hashelem, element_hash_link);
+ } else {
+ btlog->elem_linkage_un.elem_recindex_hashtbl[hashidx] = TAILQ_NEXT(hashelem, element_hash_link);
+ }
+ } else {
+ TAILQ_REMOVE(btlog->elem_linkage_un.element_hash_queue, recelem, element_hash_link);
+ }
+
+ btlog_add_elem_to_freelist(btlog, recelem);
+ btlog->active_element_count--;
+
+ num_elements_to_evict--;
+
+ assert(record->ref_count);
+
+ record->ref_count--;
+
+ if (record->ref_count == 0) {
+ btlog_add_record_to_freelist(btlog, recindex);
+
+ /*
+ * LEAKS: All done with this record. Need the next least popular record.
+ * CORRUPTION: We don't care about records. We'll just pick the next oldest element.
+ */
+
+ if (btlog->caller_will_remove_entries_for_element) {
+ break;
+ }
+ }
+
+ if (btlog->caller_will_remove_entries_for_element) {
+ recelem = TAILQ_LAST(&record->element_record_queue, _element_record_queue);
+ } else {
+ recelem = TAILQ_LAST(btlog->elem_linkage_un.element_hash_queue, _element_hash_queue);
+ recindex = recelem->recindex;
+ record = lookup_btrecord(btlog, recindex);
+ }
+ }