93
bool use_all_ram;
94
95
size_t partitions;
96
- size_t clean_size;
96
+ int64_t clean_size;
97
size_t max_dirty_pages_per_call;
98
size_t max_pages_per_inline_eviction;
99
size_t max_skip_pages_per_inline_eviction;
100
size_t max_flushes_inline;
101
size_t max_workers_evict_inline;
102
size_t additional_bytes_per_page;
103
- size_t out_of_memory_protection_bytes;
103
+ int64_t out_of_memory_protection_bytes;
104
free_clean_page_callback pgc_free_clean_cb;
105
save_dirty_page_callback pgc_save_dirty_cb;
106
save_dirty_init_callback pgc_save_init_cb;
107
PGC_OPTIONS options;
108
109
- size_t severe_pressure_per1000;
110
- size_t aggressive_evict_per1000;
111
- size_t healthy_size_per1000;
112
- size_t evict_low_threshold_per1000;
109
+ ssize_t severe_pressure_per1000;
110
+ ssize_t aggressive_evict_per1000;
111
+ ssize_t healthy_size_per1000;
112
+ ssize_t evict_low_threshold_per1000;
113
114
dynamic_target_cache_size_callback dynamic_target_size_cb;
115
nominal_page_size_callback nominal_page_size_cb;
130
131
struct {
132
SPINLOCK spinlock;
133
- size_t per1000;
133
+ ssize_t per1000;
134
} usage;
135
136
struct pgc_queue clean; // LRU is applied here to free memory from the cache
334
// ----------------------------------------------------------------------------
335
// evictions control
336
337
-static inline uint64_t pgc_threshold(size_t threshold, uint64_t wanted, uint64_t current, uint64_t clean) {
337
+static ALWAYS_INLINE int64_t pgc_threshold(ssize_t threshold, int64_t wanted, int64_t current, int64_t clean) {
338
if(current < clean)
339
current = clean;
340
341
if(wanted < current - clean)
342
wanted = current - clean;
343
344
- uint64_t ret = wanted * threshold / 1000ULL;
344
+ int64_t ret = wanted * threshold / 1000LL;
345
if(ret < current - clean)
346
ret = current - clean;
347
348
return ret;
349
}
350
351
-static inline size_t cache_usage_per1000(PGC *cache, size_t *size_to_evict) {
351
+static ssize_t cache_usage_per1000(PGC *cache, int64_t *size_to_evict) {
352
353
if(size_to_evict)
354
spinlock_lock(&cache->usage.spinlock);
356
else if(!spinlock_trylock(&cache->usage.spinlock))
357
return __atomic_load_n(&cache->usage.per1000, __ATOMIC_RELAXED);
358
359
- uint64_t wanted_cache_size;
359
+ int64_t wanted_cache_size;
360
361
- const uint64_t dirty = __atomic_load_n(&cache->dirty.stats->size, __ATOMIC_RELAXED);
362
- const uint64_t hot = __atomic_load_n(&cache->hot.stats->size, __ATOMIC_RELAXED);
363
- const uint64_t clean = __atomic_load_n(&cache->clean.stats->size, __ATOMIC_RELAXED);
364
- const uint64_t evicting = __atomic_load_n(&cache->stats.evicting_size, __ATOMIC_RELAXED);
365
- const uint64_t flushing = __atomic_load_n(&cache->stats.flushing_size, __ATOMIC_RELAXED);
366
- const uint64_t current_cache_size = __atomic_load_n(&cache->stats.size, __ATOMIC_RELAXED);
367
- const uint64_t all_pages_size = hot + dirty + clean + evicting + flushing;
368
- const uint64_t index = current_cache_size > all_pages_size ? current_cache_size - all_pages_size : 0;
369
- const uint64_t referenced_size = __atomic_load_n(&cache->stats.referenced_size, __ATOMIC_RELAXED);
361
+ const int64_t dirty = __atomic_load_n(&cache->dirty.stats->size, __ATOMIC_RELAXED);
362
+ const int64_t hot = __atomic_load_n(&cache->hot.stats->size, __ATOMIC_RELAXED);
363
+ const int64_t clean = __atomic_load_n(&cache->clean.stats->size, __ATOMIC_RELAXED);
364
+ const int64_t evicting = __atomic_load_n(&cache->stats.evicting_size, __ATOMIC_RELAXED);
365
+ const int64_t flushing = __atomic_load_n(&cache->stats.flushing_size, __ATOMIC_RELAXED);
366
+ const int64_t current_cache_size = __atomic_load_n(&cache->stats.size, __ATOMIC_RELAXED);
367
+ const int64_t all_pages_size = hot + dirty + clean + evicting + flushing;
368
+ const int64_t index = current_cache_size > all_pages_size ? current_cache_size - all_pages_size : 0;
369
+ const int64_t referenced_size = __atomic_load_n(&cache->stats.referenced_size, __ATOMIC_RELAXED);
370
371
if(cache->config.options & PGC_OPTIONS_AUTOSCALE) {
372
- const uint64_t dirty_max = __atomic_load_n(&cache->dirty.stats->max_size, __ATOMIC_RELAXED);
373
- const uint64_t hot_max = __atomic_load_n(&cache->hot.stats->max_size, __ATOMIC_RELAXED);
372
+ const int64_t dirty_max = __atomic_load_n(&cache->dirty.stats->max_size, __ATOMIC_RELAXED);
373
+ const int64_t hot_max = __atomic_load_n(&cache->hot.stats->max_size, __ATOMIC_RELAXED);
374
375
// our promise to users
376
- const uint64_t max_size1 = MAX(hot_max, hot) * 2;
376
+ const int64_t max_size1 = MAX(hot_max, hot) * 2;
377
378
// protection against slow flushing
379
- const uint64_t max_size2 = hot_max + ((dirty_max * 2 < hot_max * 2 / 3) ? hot_max * 2 / 3 : dirty_max * 2) + index;
379
+ const int64_t max_size2 = hot_max + ((dirty_max * 2 < hot_max * 2 / 3) ? hot_max * 2 / 3 : dirty_max * 2) + index;
380
381
// the final wanted cache size
382
wanted_cache_size = MIN(max_size1, max_size2);
383
384
if(cache->config.dynamic_target_size_cb) {
385
- const uint64_t wanted_cache_size_cb = cache->config.dynamic_target_size_cb();
385
+ const int64_t wanted_cache_size_cb = cache->config.dynamic_target_size_cb();
386
if(wanted_cache_size_cb > wanted_cache_size)
387
wanted_cache_size = wanted_cache_size_cb;
388
}
394
wanted_cache_size = hot + dirty + index + cache->config.clean_size;
395
396
// calculate the absolute minimum we can go
397
- const uint64_t min_cache_size1 = (referenced_size > hot ? referenced_size : hot) + dirty + index;
398
- const uint64_t min_cache_size2 = (current_cache_size > clean) ? current_cache_size - clean : min_cache_size1;
399
- const uint64_t min_cache_size = MAX(min_cache_size1, min_cache_size2);
397
+ const int64_t min_cache_size1 = (referenced_size > hot ? referenced_size : hot) + dirty + index;
398
+ const int64_t min_cache_size2 = (current_cache_size > clean) ? current_cache_size - clean : min_cache_size1;
399
+ const int64_t min_cache_size = MAX(min_cache_size1, min_cache_size2);
400
401
if(cache->config.out_of_memory_protection_bytes) {
402
// out of memory protection
404
if(sm.ram_total_bytes) {
405
// when the total exists, ram_available_bytes is also right
406
407
- const uint64_t min_available = cache->config.out_of_memory_protection_bytes;
408
- if (sm.ram_available_bytes < min_available) {
407
+ const int64_t ram_available_bytes = (int64_t)sm.ram_available_bytes;
408
+
409
+ const int64_t min_available = cache->config.out_of_memory_protection_bytes;
410
+ if (ram_available_bytes < min_available) {
411
// we must shrink
410
- uint64_t must_lose = min_available - sm.ram_available_bytes;
412
+ int64_t must_lose = min_available - ram_available_bytes;
413
414
if(current_cache_size > must_lose)
415
wanted_cache_size = current_cache_size - must_lose;
418
}
419
else if(cache->config.use_all_ram) {
420
// we can grow
419
- wanted_cache_size = current_cache_size + (sm.ram_available_bytes - min_available);
421
+ wanted_cache_size = current_cache_size + (ram_available_bytes - min_available);
422
}
423
}
424
}
431
if(unlikely(wanted_cache_size < 65536))
432
wanted_cache_size = 65536;
433
432
- const size_t per1000 = (size_t)(current_cache_size * 1000ULL / wanted_cache_size);
434
+ const ssize_t per1000 = (ssize_t)(current_cache_size * 1000LL / wanted_cache_size);
435
__atomic_store_n(&cache->usage.per1000, per1000, __ATOMIC_RELAXED);
436
__atomic_store_n(&cache->stats.wanted_cache_size, wanted_cache_size, __ATOMIC_RELAXED);
437
__atomic_store_n(&cache->stats.current_cache_size, current_cache_size, __ATOMIC_RELAXED);
438
437
- uint64_t healthy_target = pgc_threshold(cache->config.healthy_size_per1000, wanted_cache_size, current_cache_size, clean);
439
+ int64_t healthy_target = pgc_threshold(cache->config.healthy_size_per1000, wanted_cache_size, current_cache_size, clean);
440
if(current_cache_size > healthy_target) {
439
- uint64_t low_watermark_target = pgc_threshold(cache->config.evict_low_threshold_per1000, wanted_cache_size, current_cache_size, clean);
441
+ int64_t low_watermark_target = pgc_threshold(cache->config.evict_low_threshold_per1000, wanted_cache_size, current_cache_size, clean);
442
441
- uint64_t size_to_evict_now = current_cache_size - low_watermark_target;
443
+ int64_t size_to_evict_now = current_cache_size - low_watermark_target;
444
if(size_to_evict_now > clean)
445
size_to_evict_now = clean;
446
447
if(size_to_evict)
446
- *size_to_evict = (size_t)size_to_evict_now;
448
+ *size_to_evict = size_to_evict_now;
449
450
bool signal = false;
451
if(per1000 >= cache->config.severe_pressure_per1000) {
468
return per1000;
469
}
470
469
-static inline bool cache_pressure(PGC *cache, size_t limit) {
471
+static inline bool cache_pressure(PGC *cache, ssize_t limit) {
472
return (cache_usage_per1000(cache, NULL) >= limit);
473
}
474
483
static inline bool flushing_critical(PGC *cache);
484
static bool flush_pages(PGC *cache, size_t max_flushes, Word_t section, bool wait, bool all_of_them);
485
484
-static void evict_pages_inline(PGC *cache, bool on_release) {
485
- const size_t per1000 = cache_usage_per1000(cache, NULL);
486
+static ALWAYS_INLINE void evict_pages_inline(PGC *cache, bool on_release) {
487
+ const ssize_t per1000 = cache_usage_per1000(cache, NULL);
488
489
if(!(cache->config.options & PGC_OPTIONS_EVICT_PAGES_NO_INLINE)) {
490
if (per1000 > cache->config.aggressive_evict_per1000 && !on_release) {
507
}
508
}
509
508
-static inline void evict_on_clean_page_added(PGC *cache) {
510
+static ALWAYS_INLINE void evict_on_clean_page_added(PGC *cache) {
511
evict_pages_inline(cache, false);
512
}
513
512
-static inline void evict_on_page_release_when_permitted(PGC *cache) {
514
+static ALWAYS_INLINE void evict_on_page_release_when_permitted(PGC *cache) {
515
evict_pages_inline(cache, true);
516
}
517
516
-static inline void flush_inline(PGC *cache, bool on_release) {
518
+static ALWAYS_INLINE void flush_inline(PGC *cache, bool on_release) {
519
if(!(cache->config.options & PGC_OPTIONS_FLUSH_PAGES_NO_INLINE) && flushing_critical(cache)) {
520
if (on_release)
521
p2_add_fetch(&cache->stats.p2_waste_flush_on_release, 1);
526
}
527
}
528
527
-static inline void flush_on_page_add(PGC *cache) {
529
+static ALWAYS_INLINE void flush_on_page_add(PGC *cache) {
530
flush_inline(cache, false);
531
}
532
531
-static inline void flush_on_page_hot_release(PGC *cache) {
533
+static ALWAYS_INLINE void flush_on_page_hot_release(PGC *cache) {
534
flush_inline(cache, true);
535
}
536
538
// ----------------------------------------------------------------------------
539
// flushing control
540
539
-static bool flush_pages(PGC *cache, size_t max_flushes, Word_t section, bool wait, bool all_of_them);
540
-
541
static inline bool flushing_critical(PGC *cache) {
542
if(unlikely(__atomic_load_n(&cache->dirty.stats->size, __ATOMIC_RELAXED) > __atomic_load_n(&cache->hot.stats->max_size, __ATOMIC_RELAXED))) {
543
__atomic_add_fetch(&cache->stats.events_flush_critical, 1, __ATOMIC_RELAXED);
550
// ----------------------------------------------------------------------------
551
// Linked list management
552
553
-static inline void atomic_set_max(size_t *max, size_t desired) {
553
+static inline void atomic_set_max_size_t(size_t *max, size_t desired) {
554
size_t expected;
555
556
expected = __atomic_load_n(max, __ATOMIC_RELAXED);
557
558
+ do {
559
+
560
+ if(expected >= desired)
561
+ return;
562
+
563
+ } while(!__atomic_compare_exchange_n(max, &expected, desired,
564
+ false, __ATOMIC_RELAXED, __ATOMIC_RELAXED));
565
+}
566
+
567
+static inline void atomic_set_max_int64_t(int64_t *max, int64_t desired) {
568
+ int64_t expected;
569
+
570
+ expected = __atomic_load_n(max, __ATOMIC_RELAXED);
571
+
572
do {
573
574
if(expected >= desired)
605
spinlock_unlock(&spinlock);
606
}
607
594
-static ALWAYS_INLINE void
595
-pgc_stats_queue_judy_change(PGC *cache, struct pgc_queue *ll, size_t mem_before_judyl, size_t mem_after_judyl) {
596
- if(mem_after_judyl > mem_before_judyl) {
597
- __atomic_add_fetch(&ll->stats->size, mem_after_judyl - mem_before_judyl, __ATOMIC_RELAXED);
598
- __atomic_add_fetch(&cache->stats.size, mem_after_judyl - mem_before_judyl, __ATOMIC_RELAXED);
599
- }
600
- else if(mem_after_judyl < mem_before_judyl) {
601
- __atomic_sub_fetch(&ll->stats->size, mem_before_judyl - mem_after_judyl, __ATOMIC_RELAXED);
602
- __atomic_sub_fetch(&cache->stats.size, mem_before_judyl - mem_after_judyl, __ATOMIC_RELAXED);
603
- }
608
+static ALWAYS_INLINE void pgc_stats_queue_judy_change(PGC *cache, struct pgc_queue *ll, int64_t delta) {
609
+ __atomic_add_fetch(&ll->stats->size, delta, __ATOMIC_RELAXED);
610
+ __atomic_add_fetch(&cache->stats.size, delta, __ATOMIC_RELAXED);
611
}
612
606
-static ALWAYS_INLINE void pgc_stats_index_judy_change(PGC *cache, size_t mem_before_judyl, size_t mem_after_judyl) {
607
- if(mem_after_judyl > mem_before_judyl) {
608
- __atomic_add_fetch(&cache->stats.size, mem_after_judyl - mem_before_judyl, __ATOMIC_RELAXED);
609
- }
610
- else if(mem_after_judyl < mem_before_judyl) {
611
- __atomic_sub_fetch(&cache->stats.size, mem_before_judyl - mem_after_judyl, __ATOMIC_RELAXED);
612
- }
613
+static ALWAYS_INLINE void pgc_stats_index_judy_change(PGC *cache, int64_t delta) {
614
+ __atomic_add_fetch(&cache->stats.size, delta, __ATOMIC_RELAXED);
615
}
616
617
static ALWAYS_INLINE void pgc_queue_add(PGC *cache __maybe_unused, struct pgc_queue *q, PGC_PAGE *page, bool having_lock, WAITQ_PRIORITY prio __maybe_unused) {
626
if(q->linked_list_in_sections_judy) {
627
// HOT and DIRTY pages end up here.
628
627
- size_t mem_before_judyl, mem_after_judyl;
629
+ JudyAllocThreadPulseReset();
630
+ int64_t mem_delta = 0;
631
629
- mem_before_judyl = JudyLMemUsed(q->sections_judy);
632
Pvoid_t *section_pages_pptr = JudyLIns(&q->sections_judy, page->section, PJE0);
631
- mem_after_judyl = JudyLMemUsed(q->sections_judy);
633
634
struct section_pages *sp = *section_pages_pptr;
635
if(!sp) {
639
640
*section_pages_pptr = sp;
641
641
- mem_after_judyl += sizeof(struct section_pages);
642
+ mem_delta += sizeof(struct section_pages);
643
}
643
- pgc_stats_queue_judy_change(cache, q, mem_before_judyl, mem_after_judyl);
644
+
645
+ mem_delta += JudyAllocThreadPulseGetAndReset();
646
+ pgc_stats_queue_judy_change(cache, q, mem_delta);
647
648
sp->entries++;
649
sp->size += page->assumed_size;
673
pgc_queue_unlock(cache, q);
674
675
size_t entries = __atomic_add_fetch(&q->stats->entries, 1, __ATOMIC_RELAXED);
673
- size_t size = __atomic_add_fetch(&q->stats->size, page->assumed_size, __ATOMIC_RELAXED);
676
+ int64_t size = __atomic_add_fetch(&q->stats->size, page->assumed_size, __ATOMIC_RELAXED);
677
__atomic_add_fetch(&q->stats->added_entries, 1, __ATOMIC_RELAXED);
678
__atomic_add_fetch(&q->stats->added_size, page->assumed_size, __ATOMIC_RELAXED);
679
677
- atomic_set_max(&q->stats->max_entries, entries);
678
- atomic_set_max(&q->stats->max_size, size);
680
+ atomic_set_max_size_t(&q->stats->max_entries, entries);
681
+ atomic_set_max_int64_t(&q->stats->max_size, size);
682
683
if(cache->config.stats)
684
pgc_size_histogram_add(cache, &q->stats->size_histogram, page);
714
DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(sp->base, page, link.prev, link.next);
715
716
if(!sp->base) {
714
- size_t mem_before_judyl, mem_after_judyl;
717
+ JudyAllocThreadPulseReset();
718
+ int64_t mem_delta = 0;
719
716
- mem_before_judyl = JudyLMemUsed(q->sections_judy);
720
int rc = JudyLDel(&q->sections_judy, page->section, PJE0);
718
- mem_after_judyl = JudyLMemUsed(q->sections_judy);
721
722
if(!rc)
723
fatal("DBENGINE CACHE: cannot delete section from Judy LL");
724
725
// freez(sp);
726
aral_freez(pgc_sections_aral, sp);
725
- mem_after_judyl -= sizeof(struct section_pages);
726
- pgc_stats_queue_judy_change(cache, q, mem_before_judyl, mem_after_judyl);
727
+
728
+ mem_delta -= sizeof(struct section_pages);
729
+ mem_delta += JudyAllocThreadPulseGetAndReset();
730
+
731
+ pgc_stats_queue_judy_change(cache, q, mem_delta);
732
}
733
}
734
else {
865
__atomic_add_fetch(&cache->stats.referenced_size, page->assumed_size, __ATOMIC_RELAXED);
866
}
867
863
-static ALWAYS_INLINE void PGC_REFERENCED_PAGES_MINUS1(PGC *cache, size_t assumed_size) {
868
+static ALWAYS_INLINE void PGC_REFERENCED_PAGES_MINUS1(PGC *cache, int64_t assumed_size) {
869
__atomic_sub_fetch(&cache->stats.referenced_entries, 1, __ATOMIC_RELAXED);
870
__atomic_sub_fetch(&cache->stats.referenced_size, assumed_size, __ATOMIC_RELAXED);
871
}
890
static ALWAYS_INLINE void page_release(PGC *cache, PGC_PAGE *page, bool evict_if_necessary) {
891
__atomic_add_fetch(&cache->stats.releases, 1, __ATOMIC_RELAXED);
892
888
- size_t assumed_size = page->assumed_size; // take the size before we release it
893
+ int64_t assumed_size = page->assumed_size; // take the size before we release it
894
895
if(refcount_release(&page->refcount) == 0) {
896
PGC_REFERENCED_PAGES_MINUS1(cache, assumed_size);
922
static ALWAYS_INLINE bool acquired_page_get_for_deletion_or_release_it(PGC *cache __maybe_unused, PGC_PAGE *page) {
923
__atomic_add_fetch(&cache->stats.acquires_for_deletion, 1, __ATOMIC_RELAXED);
924
920
- size_t assumed_size = page->assumed_size; // take the size before we release it
925
+ int64_t assumed_size = page->assumed_size; // take the size before we release it
926
927
if(refcount_release_and_acquire_for_deletion(&page->refcount)) {
928
PGC_REFERENCED_PAGES_MINUS1(cache, assumed_size);
1013
fatal("DBENGINE CACHE: page with start time '%ld' of metric '%lu' in section '%lu' should exist, but the index returned a different address.",
1014
page->start_time_s, page->metric_id, page->section);
1015
1011
- size_t mem_before_judyl = 0, mem_after_judyl = 0;
1016
+ JudyAllocThreadPulseReset();
1017
1013
- mem_before_judyl += JudyLMemUsed(*pages_judy_pptr);
1018
if(unlikely(!JudyLDel(pages_judy_pptr, page->start_time_s, PJE0)))
1019
fatal("DBENGINE CACHE: page with start time '%ld' of metric '%lu' in section '%lu' exists, but cannot be deleted.",
1020
page->start_time_s, page->metric_id, page->section);
1017
- mem_after_judyl += JudyLMemUsed(*pages_judy_pptr);
1021
1019
- mem_before_judyl += JudyLMemUsed(*metrics_judy_pptr);
1022
if(!*pages_judy_pptr && !JudyLDel(metrics_judy_pptr, page->metric_id, PJE0))
1023
fatal("DBENGINE CACHE: metric '%lu' in section '%lu' exists and is empty, but cannot be deleted.",
1024
page->metric_id, page->section);
1023
- mem_after_judyl += JudyLMemUsed(*metrics_judy_pptr);
1025
1025
- mem_before_judyl += JudyLMemUsed(cache->index[partition].sections_judy);
1026
if(!*metrics_judy_pptr && !JudyLDel(&cache->index[partition].sections_judy, page->section, PJE0))
1027
fatal("DBENGINE CACHE: section '%lu' exists and is empty, but cannot be deleted.", page->section);
1028
- mem_after_judyl += JudyLMemUsed(cache->index[partition].sections_judy);
1028
1030
- pgc_stats_index_judy_change(cache, mem_before_judyl, mem_after_judyl);
1029
+ pgc_stats_index_judy_change(cache, JudyAllocThreadPulseGetAndReset());
1030
1031
pointer_del(cache, page);
1032
}
1066
1067
// returns true, when there is potentially more work to do
1068
static bool evict_pages_with_filter(PGC *cache, size_t max_skip, size_t max_evict, bool wait, bool all_of_them, evict_filter filter, void *data) {
1070
- size_t per1000 = cache_usage_per1000(cache, NULL);
1069
+ ssize_t per1000 = cache_usage_per1000(cache, NULL);
1070
1071
if(!all_of_them && per1000 < cache->config.healthy_size_per1000)
1072
// don't bother - not enough to do anything
1100
size_t max_pages_to_evict = 0;
1101
1102
do {
1104
- size_t max_size_to_evict = 0;
1103
+ int64_t max_size_to_evict = 0;
1104
if (unlikely(all_of_them)) {
1105
// evict them all
1106
max_size_to_evict = SIZE_MAX;
1164
1165
// find a page to evict
1166
PGC_PAGE *pages_to_evict = NULL;
1168
- size_t pages_to_evict_size = 0;
1167
+ int64_t pages_to_evict_size = 0;
1168
size_t pages_to_evict_count = 0;
1169
for(PGC_PAGE *page = cache->clean.base, *next = NULL, *first_page_we_relocated = NULL; page ; page = next) {
1170
next = page->link.next;
1291
1292
timing_dbengine_evict_step(TIMING_STEP_DBENGINE_EVICT_FREE_LOOP);
1293
1295
- size_t page_size = page->assumed_size;
1294
+ int64_t page_size = page->assumed_size;
1295
free_this_page(cache, page, partition);
1296
1297
timing_dbengine_evict_step(TIMING_STEP_DBENGINE_EVICT_FREE_PAGE);
1312
// just one page to be evicted
1313
PGC_PAGE *page = pages_to_evict;
1314
1316
- size_t page_size = page->assumed_size;
1315
+ int64_t page_size = page->assumed_size;
1316
1317
size_t partition = pgc_indexing_partition(cache, page->metric_id);
1318
pgc_index_write_lock(cache, partition);
1353
return stopped_before_finishing;
1354
}
1355
1357
-static PGC_PAGE *page_add(PGC *cache, PGC_ENTRY *entry, bool *added) {
1356
+static PGC_PAGE *pgc_page_add(PGC *cache, PGC_ENTRY *entry, bool *added) {
1357
internal_fatal(entry->start_time_s < 0 || entry->end_time_s < 0,
1358
"DBENGINE CACHE: timestamps are negative");
1359
1363
1364
#ifdef PGC_WITH_ARAL
1365
PGC_PAGE *allocation = aral_mallocz(cache->index[partition].aral);
1366
+#else
1367
+ PGC_PAGE *allocation = mallocz(sizeof(PGC_PAGE) + cache->config.additional_bytes_per_page);
1368
#endif
1369
+
1370
+ allocation->refcount = 1;
1371
+ allocation->accesses = (entry->hot) ? 0 : 1;
1372
+ allocation->flags = 0;
1373
+ allocation->section = entry->section;
1374
+ allocation->metric_id = entry->metric_id;
1375
+ allocation->start_time_s = entry->start_time_s;
1376
+ allocation->end_time_s = entry->end_time_s,
1377
+ allocation->update_every_s = entry->update_every_s,
1378
+ allocation->data = entry->data;
1379
+ allocation->assumed_size = page_assumed_size(cache, entry->size);
1380
+ spinlock_init(&allocation->transition_spinlock);
1381
+ allocation->link.prev = NULL;
1382
+ allocation->link.next = NULL;
1383
+
1384
+ if(cache->config.additional_bytes_per_page) {
1385
+ if(entry->custom_data)
1386
+ memcpy(allocation->custom_data, entry->custom_data, cache->config.additional_bytes_per_page);
1387
+ else
1388
+ memset(allocation->custom_data, 0, cache->config.additional_bytes_per_page);
1389
+ }
1390
+
1391
PGC_PAGE *page;
1392
size_t spins = 0;
1393
1402
1403
pgc_index_write_lock(cache, partition);
1404
1382
- size_t mem_before_judyl = 0, mem_after_judyl = 0;
1405
+ JudyAllocThreadPulseReset();
1406
1384
- mem_before_judyl += JudyLMemUsed(cache->index[partition].sections_judy);
1407
Pvoid_t *metrics_judy_pptr = JudyLIns(&cache->index[partition].sections_judy, entry->section, PJE0);
1408
if(unlikely(!metrics_judy_pptr || metrics_judy_pptr == PJERR))
1409
fatal("DBENGINE CACHE: corrupted sections judy array");
1388
- mem_after_judyl += JudyLMemUsed(cache->index[partition].sections_judy);
1410
1390
- mem_before_judyl += JudyLMemUsed(*metrics_judy_pptr);
1411
Pvoid_t *pages_judy_pptr = JudyLIns(metrics_judy_pptr, entry->metric_id, PJE0);
1412
if(unlikely(!pages_judy_pptr || pages_judy_pptr == PJERR))
1413
fatal("DBENGINE CACHE: corrupted pages judy array");
1394
- mem_after_judyl += JudyLMemUsed(*metrics_judy_pptr);
1414
1396
- mem_before_judyl += JudyLMemUsed(*pages_judy_pptr);
1415
Pvoid_t *page_ptr = JudyLIns(pages_judy_pptr, entry->start_time_s, PJE0);
1416
if(unlikely(!page_ptr || page_ptr == PJERR))
1417
fatal("DBENGINE CACHE: corrupted page in judy array");
1400
- mem_after_judyl += JudyLMemUsed(*pages_judy_pptr);
1418
1402
- pgc_stats_index_judy_change(cache, mem_before_judyl, mem_after_judyl);
1419
+ pgc_stats_index_judy_change(cache, JudyAllocThreadPulseGetAndReset());
1420
1421
page = *page_ptr;
1422
1423
if (likely(!page)) {
1407
-#ifdef PGC_WITH_ARAL
1424
+ // consume it
1425
page = allocation;
1426
allocation = NULL;
1410
-#else
1411
- page = mallocz(sizeof(PGC_PAGE) + cache->config.additional_bytes_per_page);
1412
-#endif
1413
- page->refcount = 1;
1414
- page->accesses = (entry->hot) ? 0 : 1;
1415
- page->flags = 0;
1416
- page->section = entry->section;
1417
- page->metric_id = entry->metric_id;
1418
- page->start_time_s = entry->start_time_s;
1419
- page->end_time_s = entry->end_time_s,
1420
- page->update_every_s = entry->update_every_s,
1421
- page->data = entry->data;
1422
- page->assumed_size = page_assumed_size(cache, entry->size);
1423
- spinlock_init(&page->transition_spinlock);
1424
- page->link.prev = NULL;
1425
- page->link.next = NULL;
1426
-
1427
- if(cache->config.additional_bytes_per_page) {
1428
- if(entry->custom_data)
1429
- memcpy(page->custom_data, entry->custom_data, cache->config.additional_bytes_per_page);
1430
- else
1431
- memset(page->custom_data, 0, cache->config.additional_bytes_per_page);
1432
- }
1433
-
1427
+
1428
// put it in the index
1429
*page_ptr = page;
1430
pointer_add(cache, page);
1465
1466
} while(!page);
1467
1468
+ if(allocation) {
1469
#ifdef PGC_WITH_ARAL
1475
- if(allocation)
1470
aral_freez(cache->index[partition].aral, allocation);
1471
+#else
1472
+ freez(allocation);
1473
#endif
1474
+ }
1475
1476
if(spins > 1)
1477
p2_add_fetch(&cache->stats.p2_waste_insert_spins, spins - 1);
1731
1732
PGC_ENTRY array[optimal_flush_size];
1733
PGC_PAGE *pages[optimal_flush_size];
1737
- size_t pages_added = 0, pages_added_size = 0;
1738
- size_t pages_removed_dirty = 0, pages_removed_dirty_size = 0;
1739
- size_t pages_cancelled = 0, pages_cancelled_size = 0;
1740
- size_t pages_made_clean = 0, pages_made_clean_size = 0;
1734
+
1735
+ size_t pages_added = 0,
1736
+ pages_removed_dirty = 0,
1737
+ pages_cancelled = 0,
1738
+ pages_made_clean = 0;
1739
+
1740
+ int64_t pages_added_size = 0,
1741
+ pages_removed_dirty_size = 0,
1742
+ pages_cancelled_size = 0,
1743
+ pages_made_clean_size = 0;
1744
1745
PGC_PAGE *page = sp->base;
1746
while (page && pages_added < optimal_flush_size) {
1927
if (nd_thread_signaled_to_cancel())
1928
break;
1929
1927
- size_t size_to_evict = 0;
1930
+ int64_t size_to_evict = 0;
1931
bool system_cleanup = false;
1932
if(cache_usage_per1000(cache, &size_to_evict) > cache->config.aggressive_evict_per1000)
1933
system_cleanup = true;
1989
cache->config.pgc_save_dirty_cb = pgc_save_dirty_cb;
1990
1991
// eviction strategy
1989
- cache->config.clean_size = (clean_size_bytes < 1 * 1024 * 1024) ? 1 * 1024 * 1024 : clean_size_bytes;
1992
+ cache->config.clean_size = (clean_size_bytes < 1 * 1024 * 1024) ? 1 * 1024 * 1024 : (int64_t)clean_size_bytes;
1993
cache->config.pgc_free_clean_cb = pgc_free_cb;
1994
cache->config.max_workers_evict_inline = max_inline_evictors;
1995
cache->config.max_pages_per_inline_eviction = max_pages_per_inline_eviction;
2003
2004
// use all ram and protection from out of memory
2005
cache->config.use_all_ram = dbengine_use_all_ram_for_caches;
2003
- cache->config.out_of_memory_protection_bytes = dbengine_out_of_memory_protection;
2006
+ cache->config.out_of_memory_protection_bytes = (int64_t)dbengine_out_of_memory_protection;
2007
2008
// partitions
2009
if(partitions == 0) partitions = netdata_conf_cpus();
2118
}
2119
}
2120
2118
-PGC_PAGE *pgc_page_add_and_acquire(PGC *cache, PGC_ENTRY entry, bool *added) {
2119
- return page_add(cache, &entry, added);
2121
+ALWAYS_INLINE PGC_PAGE *pgc_page_add_and_acquire(PGC *cache, PGC_ENTRY entry, bool *added) {
2122
+ return pgc_page_add(cache, &entry, added);
2123
}
2124
2122
-PGC_PAGE *pgc_page_dup(PGC *cache, PGC_PAGE *page) {
2125
+ALWAYS_INLINE PGC_PAGE *pgc_page_dup(PGC *cache, PGC_PAGE *page) {
2126
if(!page_acquire(cache, page))
2127
fatal("DBENGINE CACHE: tried to dup a page that is not acquired!");
2128
2133
page_release(cache, page, is_page_clean(page));
2134
}
2135
2133
-void pgc_page_hot_to_dirty_and_release(PGC *cache, PGC_PAGE *page, bool never_flush) {
2136
+ALWAYS_INLINE void pgc_page_hot_to_dirty_and_release(PGC *cache, PGC_PAGE *page, bool never_flush) {
2137
p2_add_fetch(&cache->stats.p2_workers_hot2dirty, 1);
2138
2139
//#ifdef NETDATA_INTERNAL_CHECKS
2243
2244
void pgc_reset_hot_max(PGC *cache) {
2245
size_t entries = __atomic_load_n(&cache->hot.stats->entries, __ATOMIC_RELAXED);
2243
- size_t size = __atomic_load_n(&cache->hot.stats->size, __ATOMIC_RELAXED);
2246
+ int64_t size = __atomic_load_n(&cache->hot.stats->size, __ATOMIC_RELAXED);
2247
2248
__atomic_store_n(&cache->hot.stats->max_entries, entries, __ATOMIC_RELAXED);
2249
__atomic_store_n(&cache->hot.stats->max_size, size, __ATOMIC_RELAXED);
2250
2248
- size_t size_to_evict = 0;
2251
+ int64_t size_to_evict = 0;
2252
cache_usage_per1000(cache, &size_to_evict);
2253
evict_pages(cache, 0, 0, true, false);
2254
}
2258
cache->config.out_of_memory_protection_bytes = 0;
2259
cache->config.use_all_ram = false;
2260
2258
- size_t size_to_evict = 0;
2261
+ int64_t size_to_evict = 0;
2262
cache_usage_per1000(cache, &size_to_evict);
2263
evict_pages(cache, 0, 0, true, false);
2264
}
2267
cache->config.nominal_page_size_cb = callback;
2268
}
2269
2267
-size_t pgc_get_current_cache_size(PGC *cache) {
2270
+int64_t pgc_get_current_cache_size(PGC *cache) {
2271
return __atomic_load_n(&cache->stats.current_cache_size, __ATOMIC_RELAXED);
2272
}
2273
2271
-size_t pgc_get_wanted_cache_size(PGC *cache) {
2274
+int64_t pgc_get_wanted_cache_size(PGC *cache) {
2275
return __atomic_load_n(&cache->stats.wanted_cache_size, __ATOMIC_RELAXED);
2276
}
2277
2310
if(queue_stats && cache->config.stats)
2311
pgc_size_histogram_del(cache, &queue_stats->size_histogram, page);
2312
2310
- size_t old_assumed_size = page->assumed_size;
2313
+ int64_t old_assumed_size = page->assumed_size;
2314
2315
size_t old_size = page_size_from_assumed_size(cache, old_assumed_size);
2316
size_t size = old_size + additional_bytes;
2317
page->assumed_size = page_assumed_size(cache, size);
2318
2316
- size_t delta = page->assumed_size - old_assumed_size;
2319
+ int64_t delta = page->assumed_size - old_assumed_size;
2320
__atomic_add_fetch(&cache->stats.size, delta, __ATOMIC_RELAXED);
2321
__atomic_add_fetch(&cache->stats.added_size, delta, __ATOMIC_RELAXED);
2322
__atomic_add_fetch(&cache->stats.referenced_size, delta, __ATOMIC_RELAXED);