move sort functions into ppagecache

This commit is contained in:
Levi Neely 2025-03-15 10:19:46 +01:00
parent f714a06048
commit 0b128ba9db
4 changed files with 325 additions and 333 deletions

View File

@ -165,325 +165,3 @@ int psync_match_pattern(const char *name, const char *pattern, size_t plen) {
}
return name[i] == 0;
}
static uint32_t pq_rnd() {
static uint32_t a = 0x95ae3d25, b = 0xe225d755, c = 0xc63a2ae7,
d = 0xe4556265;
uint32_t e = a - rot(b, 27);
a = b ^ rot(c, 17);
b = c + d;
c = d + e;
d = e + a;
return d;
}
#define QSORT_TRESH 8
#define QSORT_MTR 64
#define QSORT_REC_M (16 * 1024)
static inline void sw2(unsigned char **a, unsigned char **b) {
unsigned char *tmp = *a;
*a = *b;
*b = tmp;
}
static unsigned char *med5(unsigned char *a, unsigned char *b, unsigned char *c,
unsigned char *d, unsigned char *e,
int (*compar)(const void *, const void *)) {
if (compar(b, a) < 0)
sw2(&a, &b);
if (compar(d, c) < 0)
sw2(&c, &d);
if (compar(a, c) < 0) {
a = e;
if (compar(b, a) < 0)
sw2(&a, &b);
} else {
c = e;
if (compar(d, c) < 0)
sw2(&c, &d);
}
if (compar(a, c) < 0)
a = b;
else
c = d;
if (compar(a, c) < 0)
return a;
else
return c;
}
unsigned char *pq_choose_part(unsigned char *base, size_t cnt, size_t size,
int (*compar)(const void *, const void *)) {
if (cnt >= QSORT_REC_M) {
cnt /= 5;
return med5(pq_choose_part(base, cnt, size, compar),
pq_choose_part(base + cnt * size, cnt, size, compar),
pq_choose_part(base + cnt * size * 2, cnt, size, compar),
pq_choose_part(base + cnt * size * 3, cnt, size, compar),
pq_choose_part(base + cnt * size * 4, cnt, size, compar),
compar);
} else {
return med5(base + (pq_rnd() % cnt) * size, base + (pq_rnd() % cnt) * size,
base + (pq_rnd() % cnt) * size, base + (pq_rnd() % cnt) * size,
base + (pq_rnd() % cnt) * size, compar);
}
}
static inline void pqsswap(unsigned char *a, unsigned char *b, size_t size) {
unsigned char tmp;
do {
tmp = *a;
*a++ = *b;
*b++ = tmp;
} while (--size);
}
static inline void pqsswap32(unsigned char *a, unsigned char *b, size_t size) {
uint32_t tmp;
do {
tmp = *(uint32_t *)a;
*(uint32_t *)a = *(uint32_t *)b;
*(uint32_t *)b = tmp;
a += sizeof(uint32_t);
b += sizeof(uint32_t);
} while (--size);
}
typedef struct {
unsigned char *lo;
unsigned char *hi;
} psq_stack_t;
void psync_pqsort(void *base, size_t cnt, size_t sort_first, size_t size,
int (*compar)(const void *, const void *)) {
psq_stack_t stack[sizeof(size_t) * 8];
psq_stack_t *top;
unsigned char *lo, *hi, *mid, *l, *r, *sf;
size_t tresh, n, u32size;
lo = NULL;
hi = NULL;
mid = NULL;
l = NULL;
r = NULL;
sf = NULL;
tresh = QSORT_TRESH * size;
sf = (unsigned char *)base + sort_first * size;
if (size % sizeof(uint32_t) == 0 && (uintptr_t)base % sizeof(uint32_t) == 0)
u32size = size / sizeof(uint32_t);
else
u32size = 0;
if (cnt > QSORT_TRESH) {
top = stack + 1;
lo = (unsigned char *)base;
hi = lo + (cnt - 1) * size;
do {
n = (hi - lo) / size;
if (n <= QSORT_MTR) {
mid = lo + (n >> 1) * size;
if (compar(mid, lo) < 0)
pqsswap(mid, lo, size);
if (compar(hi, mid) < 0) {
pqsswap(mid, hi, size);
if (compar(mid, lo) < 0)
pqsswap(mid, lo, size);
}
// we already sure *hi and *lo are good, so they will be skipped without
// checking
l = lo;
r = hi;
} else {
mid = pq_choose_part(lo, n, size, compar);
l = lo - size;
r = hi + size;
}
if (u32size) {
do {
do {
l += size;
} while (compar(l, mid) < 0);
do {
r -= size;
} while (compar(mid, r) < 0);
if (l >= r)
break;
pqsswap32(l, r, u32size);
if (mid == l) {
mid = r;
r += size;
} else if (mid == r) {
mid = l;
l -= size;
}
} while (1);
} else {
do {
do {
l += size;
} while (compar(l, mid) < 0);
do {
r -= size;
} while (compar(mid, r) < 0);
if (l >= r)
break;
pqsswap(l, r, size);
if (mid == l) {
mid = r;
r += size;
} else if (mid == r) {
mid = l;
l -= size;
}
} while (1);
}
if (hi - mid <= tresh || mid >= sf) {
if (mid - lo <= tresh) {
top--;
lo = top->lo;
hi = top->hi;
} else {
hi = mid - size;
}
} else if (mid - lo <= tresh) {
lo = mid + size;
} else if (hi - mid < mid - lo) {
top->lo = lo;
top->hi = mid - size;
top++;
lo = mid + size;
} else {
top->lo = mid + size;
top->hi = hi;
top++;
hi = mid - size;
}
} while (top != stack);
} else if (cnt <= 1) {
return;
}
lo = (unsigned char *)base;
hi = lo + (cnt - 1) * size;
sf += size * QSORT_TRESH;
if (sf < hi)
hi = sf;
r = lo + QSORT_TRESH * size + 4;
if (r > hi)
r = hi;
for (l = lo + size; l <= r; l += size)
if (compar(l, lo) < 0)
lo = l;
pqsswap((unsigned char *)base, lo, size);
l = (unsigned char *)base + size;
hi -= size;
while (l <= hi) {
lo = l;
l += size;
while (compar(l, lo) < 0)
lo -= size;
lo += size;
if (lo != l) {
unsigned char *t = l + size;
if (u32size) {
while ((t -= sizeof(uint32_t)) >= l) {
uint32_t tmp = *(uint32_t *)t;
for (r = mid = t; (mid -= size) >= lo; r = mid)
*(uint32_t *)r = *(uint32_t *)mid;
*(uint32_t *)r = tmp;
}
} else {
while (--t >= l) {
unsigned char tmp = *t;
for (r = mid = t; (mid -= size) >= lo; r = mid)
*r = *mid;
*r = tmp;
}
}
}
}
}
void psync_qpartition(void *base, size_t cnt, size_t sort_first, size_t size,
int (*compar)(const void *, const void *)) {
unsigned char *lo, *hi, *mid, *l, *r, *sf;
size_t n, u32size;
sf = (unsigned char *)base + sort_first * size;
if (size % sizeof(uint32_t) == 0 && (uintptr_t)base % sizeof(uint32_t) == 0)
u32size = size / sizeof(uint32_t);
else
u32size = 0;
if (cnt <= 1) // otherwise cnt-1 will underflow
return;
lo = (unsigned char *)base;
hi = lo + (cnt - 1) * size;
while (1) {
n = (hi - lo) / size;
if (n <= QSORT_MTR) {
mid = lo + (n >> 1) * size;
if (compar(mid, lo) < 0)
pqsswap(mid, lo, size);
if (compar(hi, mid) < 0) {
pqsswap(mid, hi, size);
if (compar(mid, lo) < 0)
pqsswap(mid, lo, size);
}
// we already sure *hi and *lo are good, so they will be skipped without
// checking
if (n <= 2) // when n is 2, we have 3 elements
return;
l = lo;
r = hi;
} else {
mid = pq_choose_part(lo, n, size, compar);
l = lo - size;
r = hi + size;
}
if (u32size) {
do {
do {
l += size;
} while (compar(l, mid) < 0);
do {
r -= size;
} while (compar(mid, r) < 0);
if (l >= r)
break;
pqsswap32(l, r, u32size);
if (mid == l) {
mid = r;
r += size;
} else if (mid == r) {
mid = l;
l -= size;
}
} while (1);
} else {
do {
do {
l += size;
} while (compar(l, mid) < 0);
do {
r -= size;
} while (compar(mid, r) < 0);
if (l >= r)
break;
pqsswap(l, r, size);
if (mid == l) {
mid = r;
r += size;
} else if (mid == r) {
mid = l;
l -= size;
}
} while (1);
}
if (mid < sf)
lo = mid + size;
else if (mid > sf)
hi = mid - size;
else
return;
}
}

View File

@ -156,15 +156,10 @@ extern PSYNC_THREAD uint32_t psync_error;
extern uint16_t const *__hex_lookup;
int psync_rename_conflicted_file(const char *path);
void psync_run_after_sec(psync_run_after_t run, void *ptr, uint32_t seconds);
void psync_free_after_sec(void *ptr, uint32_t seconds);
int psync_match_pattern(const char *name, const char *pattern, size_t plen);
void psync_pqsort(void *base, size_t cnt, size_t sort_first, size_t size, int (*compar)(const void *, const void *));
void psync_qpartition(void *base, size_t cnt, size_t sort_first, size_t size, int (*compar)(const void *, const void *));
/* needs 12 characters of buffer space on top of the length of the prefix */
static inline void psync_get_string_id(char *dst, const char *prefix, uint64_t id) {
size_t plen;

View File

@ -66,6 +66,10 @@
#define PAGE_TASK_TYPE_CREAT 0
#define PAGE_TASK_TYPE_MODIFY 1
#define QSORT_TRESH 8
#define QSORT_MTR 64
#define QSORT_REC_M (16 * 1024)
#define pagehash_by_hash_and_pageid(hash, pageid) \
(((hash) + (pageid)) % CACHE_HASH)
#define waiterhash_by_hash_and_pageid(hash, pageid) \
@ -161,6 +165,11 @@ typedef struct {
uint8_t freebuff;
} psync_crypto_data_page;
typedef struct {
unsigned char *lo;
unsigned char *hi;
} psq_stack_t;
static psync_list cache_hash[CACHE_HASH];
static uint32_t cache_pages_in_hash = 0;
static uint32_t cache_pages_free;
@ -989,6 +998,320 @@ static int pagecache_entry_cmp_xfirst_pages(const void *p1, const void *p2) {
return (int)((int64_t)e2->lastuse - (int64_t)e1->lastuse);
}
static inline void sw2(unsigned char **a, unsigned char **b) {
unsigned char *tmp = *a;
*a = *b;
*b = tmp;
}
static unsigned char *med5(unsigned char *a, unsigned char *b, unsigned char *c,
unsigned char *d, unsigned char *e,
int (*compar)(const void *, const void *)) {
if (compar(b, a) < 0)
sw2(&a, &b);
if (compar(d, c) < 0)
sw2(&c, &d);
if (compar(a, c) < 0) {
a = e;
if (compar(b, a) < 0)
sw2(&a, &b);
} else {
c = e;
if (compar(d, c) < 0)
sw2(&c, &d);
}
if (compar(a, c) < 0)
a = b;
else
c = d;
if (compar(a, c) < 0)
return a;
else
return c;
}
static uint32_t pq_rnd() {
static uint32_t a = 0x95ae3d25, b = 0xe225d755, c = 0xc63a2ae7,
d = 0xe4556265;
uint32_t e = a - rot(b, 27);
a = b ^ rot(c, 17);
b = c + d;
c = d + e;
d = e + a;
return d;
}
static unsigned char *pq_choose_part(unsigned char *base, size_t cnt, size_t size,
int (*compar)(const void *, const void *)) {
if (cnt >= QSORT_REC_M) {
cnt /= 5;
return med5(pq_choose_part(base, cnt, size, compar),
pq_choose_part(base + cnt * size, cnt, size, compar),
pq_choose_part(base + cnt * size * 2, cnt, size, compar),
pq_choose_part(base + cnt * size * 3, cnt, size, compar),
pq_choose_part(base + cnt * size * 4, cnt, size, compar),
compar);
} else {
return med5(base + (pq_rnd() % cnt) * size, base + (pq_rnd() % cnt) * size,
base + (pq_rnd() % cnt) * size, base + (pq_rnd() % cnt) * size,
base + (pq_rnd() % cnt) * size, compar);
}
}
static inline void pqsswap(unsigned char *a, unsigned char *b, size_t size) {
unsigned char tmp;
do {
tmp = *a;
*a++ = *b;
*b++ = tmp;
} while (--size);
}
static inline void pqsswap32(unsigned char *a, unsigned char *b, size_t size) {
uint32_t tmp;
do {
tmp = *(uint32_t *)a;
*(uint32_t *)a = *(uint32_t *)b;
*(uint32_t *)b = tmp;
a += sizeof(uint32_t);
b += sizeof(uint32_t);
} while (--size);
}
static void psync_pqsort(void *base, size_t cnt, size_t sort_first, size_t size,
int (*compar)(const void *, const void *)) {
psq_stack_t stack[sizeof(size_t) * 8];
psq_stack_t *top;
unsigned char *lo, *hi, *mid, *l, *r, *sf;
size_t tresh, n, u32size;
lo = NULL;
hi = NULL;
mid = NULL;
l = NULL;
r = NULL;
sf = NULL;
tresh = QSORT_TRESH * size;
sf = (unsigned char *)base + sort_first * size;
if (size % sizeof(uint32_t) == 0 && (uintptr_t)base % sizeof(uint32_t) == 0)
u32size = size / sizeof(uint32_t);
else
u32size = 0;
if (cnt > QSORT_TRESH) {
top = stack + 1;
lo = (unsigned char *)base;
hi = lo + (cnt - 1) * size;
do {
n = (hi - lo) / size;
if (n <= QSORT_MTR) {
mid = lo + (n >> 1) * size;
if (compar(mid, lo) < 0)
pqsswap(mid, lo, size);
if (compar(hi, mid) < 0) {
pqsswap(mid, hi, size);
if (compar(mid, lo) < 0)
pqsswap(mid, lo, size);
}
// we already sure *hi and *lo are good, so they will be skipped without
// checking
l = lo;
r = hi;
} else {
mid = pq_choose_part(lo, n, size, compar);
l = lo - size;
r = hi + size;
}
if (u32size) {
do {
do {
l += size;
} while (compar(l, mid) < 0);
do {
r -= size;
} while (compar(mid, r) < 0);
if (l >= r)
break;
pqsswap32(l, r, u32size);
if (mid == l) {
mid = r;
r += size;
} else if (mid == r) {
mid = l;
l -= size;
}
} while (1);
} else {
do {
do {
l += size;
} while (compar(l, mid) < 0);
do {
r -= size;
} while (compar(mid, r) < 0);
if (l >= r)
break;
pqsswap(l, r, size);
if (mid == l) {
mid = r;
r += size;
} else if (mid == r) {
mid = l;
l -= size;
}
} while (1);
}
if (hi - mid <= tresh || mid >= sf) {
if (mid - lo <= tresh) {
top--;
lo = top->lo;
hi = top->hi;
} else {
hi = mid - size;
}
} else if (mid - lo <= tresh) {
lo = mid + size;
} else if (hi - mid < mid - lo) {
top->lo = lo;
top->hi = mid - size;
top++;
lo = mid + size;
} else {
top->lo = mid + size;
top->hi = hi;
top++;
hi = mid - size;
}
} while (top != stack);
} else if (cnt <= 1) {
return;
}
lo = (unsigned char *)base;
hi = lo + (cnt - 1) * size;
sf += size * QSORT_TRESH;
if (sf < hi)
hi = sf;
r = lo + QSORT_TRESH * size + 4;
if (r > hi)
r = hi;
for (l = lo + size; l <= r; l += size)
if (compar(l, lo) < 0)
lo = l;
pqsswap((unsigned char *)base, lo, size);
l = (unsigned char *)base + size;
hi -= size;
while (l <= hi) {
lo = l;
l += size;
while (compar(l, lo) < 0)
lo -= size;
lo += size;
if (lo != l) {
unsigned char *t = l + size;
if (u32size) {
while ((t -= sizeof(uint32_t)) >= l) {
uint32_t tmp = *(uint32_t *)t;
for (r = mid = t; (mid -= size) >= lo; r = mid)
*(uint32_t *)r = *(uint32_t *)mid;
*(uint32_t *)r = tmp;
}
} else {
while (--t >= l) {
unsigned char tmp = *t;
for (r = mid = t; (mid -= size) >= lo; r = mid)
*r = *mid;
*r = tmp;
}
}
}
}
}
static void psync_qpartition(void *base, size_t cnt, size_t sort_first, size_t size,
int (*compar)(const void *, const void *)) {
unsigned char *lo, *hi, *mid, *l, *r, *sf;
size_t n, u32size;
sf = (unsigned char *)base + sort_first * size;
if (size % sizeof(uint32_t) == 0 && (uintptr_t)base % sizeof(uint32_t) == 0)
u32size = size / sizeof(uint32_t);
else
u32size = 0;
if (cnt <= 1) // otherwise cnt-1 will underflow
return;
lo = (unsigned char *)base;
hi = lo + (cnt - 1) * size;
while (1) {
n = (hi - lo) / size;
if (n <= QSORT_MTR) {
mid = lo + (n >> 1) * size;
if (compar(mid, lo) < 0)
pqsswap(mid, lo, size);
if (compar(hi, mid) < 0) {
pqsswap(mid, hi, size);
if (compar(mid, lo) < 0)
pqsswap(mid, lo, size);
}
// we already sure *hi and *lo are good, so they will be skipped without
// checking
if (n <= 2) // when n is 2, we have 3 elements
return;
l = lo;
r = hi;
} else {
mid = pq_choose_part(lo, n, size, compar);
l = lo - size;
r = hi + size;
}
if (u32size) {
do {
do {
l += size;
} while (compar(l, mid) < 0);
do {
r -= size;
} while (compar(mid, r) < 0);
if (l >= r)
break;
pqsswap32(l, r, u32size);
if (mid == l) {
mid = r;
r += size;
} else if (mid == r) {
mid = l;
l -= size;
}
} while (1);
} else {
do {
do {
l += size;
} while (compar(l, mid) < 0);
do {
r -= size;
} while (compar(mid, r) < 0);
if (l >= r)
break;
pqsswap(l, r, size);
if (mid == l) {
mid = r;
r += size;
} else if (mid == r) {
mid = l;
l -= size;
}
} while (1);
}
if (mid < sf)
lo = mid + size;
else if (mid > sf)
hi = mid - size;
else
return;
}
}
/* sum should be around 90-95 percent, so after a run cache get smaller */
#define PSYNC_FS_CACHE_LRU_PERCENT 40
#define PSYNC_FS_CACHE_LRU2_PERCENT 20

View File

@ -11,7 +11,6 @@
#include "pdbg.h"
#include "putil.h"
static char normalize_table[256];
const char base64_table[] = {
@ -47,11 +46,8 @@ __attribute((constructor)) static void init() {
normalize_table['\\'] = '_';
}
// wipe a segment of memory mem of size sz using a DoD 5220.22-M compliant
// 3-pass wipe. the first pass overwrites the memory with zeroes, the second
// with ones, and the third with random data using the urandom entropy
// source. if the urandom source fails, it falls back to a simple
// (non-cryptographically-secure) RNG.
// putil_wipe wipes a segment of memory mem of size sz using a DoD 5220.22-M
// compliant 3-pass wipe.
void putil_wipe(void *mem, size_t sz) {
if (!mem || sz == 0) { return; }