Skip to content

Commit 9586856

Browse files
author
virco
committed
improve pagecache garbage collection by using hand-written partial sort (that works acceptably well for full sort as well)
1 parent 6f363cf commit 9586856

File tree

3 files changed

+272
-50
lines changed

3 files changed

+272
-50
lines changed

plibs.c

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2022,6 +2022,202 @@ int psync_task_complete(void *h, void *data){
20222022
return ret;
20232023
}
20242024

2025+
2026+
#define rot(x,k) (((x)<<(k))|((x)>>(32-(k))))
2027+
static uint32_t pq_rnd() {
2028+
static uint32_t a=0x95ae3d25, b=0xe225d755, c=0xc63a2ae7, d=0xe4556265;
2029+
uint32_t e=a-rot(b, 27);
2030+
a=b^rot(c, 17);
2031+
b=c+d;
2032+
c=d+e;
2033+
d=e+a;
2034+
return d;
2035+
}
2036+
2037+
#define QSORT_TRESH 8
2038+
#define QSORT_MTR 64
2039+
#define QSORT_REC_M (16*1024)
2040+
2041+
static inline unsigned char *med3(unsigned char *a, unsigned char *b, unsigned char *c, int (*compar)(const void *, const void *)) {
2042+
return compar(a, b)<0?
2043+
(compar(b, c)<0?b:compar(a, c)<0?c:a):
2044+
(compar(b, c)>0?b:compar(a, c)>0?c:a);
2045+
}
2046+
2047+
unsigned char *pq_choose_part(unsigned char *base, size_t cnt, size_t size, int (*compar)(const void *, const void *)) {
2048+
if (cnt>=QSORT_REC_M) {
2049+
cnt/=3;
2050+
return med3(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), compar);
2051+
} else {
2052+
return med3(base+(pq_rnd()%cnt)*size, base+(pq_rnd()%cnt)*size, base+(pq_rnd()%cnt)*size, compar);
2053+
}
2054+
}
2055+
2056+
static inline void pqsswap(unsigned char *a, unsigned char *b, size_t size) {
2057+
unsigned char tmp;
2058+
do {
2059+
tmp=*a;
2060+
*a++=*b;
2061+
*b++=tmp;
2062+
} while (--size);
2063+
}
2064+
2065+
static inline void pqsswap32(unsigned char *a, unsigned char *b, size_t size) {
2066+
uint32_t tmp;
2067+
do {
2068+
tmp=*(uint32_t *)a;
2069+
*(uint32_t *)a=*(uint32_t *)b;
2070+
*(uint32_t *)b=tmp;
2071+
a+=sizeof(uint32_t);
2072+
b+=sizeof(uint32_t);
2073+
} while (--size);
2074+
}
2075+
2076+
2077+
typedef struct {
2078+
unsigned char *lo;
2079+
unsigned char *hi;
2080+
} psq_stack_t;
2081+
2082+
void psync_pqsort(void *base, size_t cnt, size_t sort_first, size_t size, int (*compar)(const void *, const void *)) {
2083+
psq_stack_t stack[sizeof(size_t)*8];
2084+
psq_stack_t *top;
2085+
unsigned char *lo, *hi, *mid, *l, *r, *sf;
2086+
size_t tresh, n, u32size;
2087+
tresh=QSORT_TRESH*size;
2088+
sf=(unsigned char *)base+sort_first*size;
2089+
if (size%sizeof(uint32_t)==0 && (uintptr_t)base%sizeof(uint32_t)==0)
2090+
u32size=size/sizeof(uint32_t);
2091+
else
2092+
u32size=0;
2093+
if (cnt>QSORT_TRESH) {
2094+
top=stack+1;
2095+
lo=(unsigned char *)base;
2096+
hi=lo+(cnt-1)*size;
2097+
do {
2098+
n=(hi-lo)/size;
2099+
if (n<=QSORT_MTR) {
2100+
mid=lo+(n>>1)*size;
2101+
if (compar(mid, lo)<0)
2102+
pqsswap(mid, lo, size);
2103+
if (compar(hi, mid)<0) {
2104+
pqsswap(mid, hi, size);
2105+
if (compar(mid, lo)<0)
2106+
pqsswap(mid, lo, size);
2107+
}
2108+
// we already sure *hi and *lo are good, so they will be skipped without checking
2109+
l=lo;
2110+
r=hi;
2111+
} else {
2112+
mid=pq_choose_part(lo, n, size, compar);
2113+
l=lo-size;
2114+
r=hi+size;
2115+
}
2116+
if (u32size) {
2117+
do {
2118+
do {
2119+
l+=size;
2120+
} while (compar(l, mid)<0);
2121+
do {
2122+
r-=size;
2123+
} while (compar(mid, r)<0);
2124+
if (l>=r)
2125+
break;
2126+
pqsswap32(l, r, u32size);
2127+
if (mid==l) {
2128+
mid=r;
2129+
r+=size;
2130+
} else if (mid==r) {
2131+
mid=l;
2132+
l-=size;
2133+
}
2134+
} while (1);
2135+
} else {
2136+
do {
2137+
do {
2138+
l+=size;
2139+
} while (compar(l, mid)<0);
2140+
do {
2141+
r-=size;
2142+
} while (compar(mid, r)<0);
2143+
if (l>=r)
2144+
break;
2145+
pqsswap(l, r, size);
2146+
if (mid==l) {
2147+
mid=r;
2148+
r+=size;
2149+
} else if (mid==r) {
2150+
mid=l;
2151+
l-=size;
2152+
}
2153+
} while (1);
2154+
}
2155+
if (hi-mid<=tresh || mid>=sf) {
2156+
if (mid-lo<=tresh) {
2157+
top--;
2158+
lo=top->lo;
2159+
hi=top->hi;
2160+
} else {
2161+
hi=mid-size;
2162+
}
2163+
} else if (mid-lo<=tresh) {
2164+
lo=mid+size;
2165+
} else if (hi-mid<mid-lo) {
2166+
top->lo=lo;
2167+
top->hi=mid-size;
2168+
top++;
2169+
lo=mid+size;
2170+
} else {
2171+
top->lo=mid+size;
2172+
top->hi=hi;
2173+
top++;
2174+
hi=mid-size;
2175+
}
2176+
} while (top!=stack);
2177+
} else if (cnt<=1) {
2178+
return;
2179+
}
2180+
lo=(unsigned char *)base;
2181+
hi=lo+(cnt-1)*size;
2182+
sf+=size*QSORT_TRESH;
2183+
if (sf<hi)
2184+
hi=sf;
2185+
r=lo+QSORT_TRESH*size+4;
2186+
if (r>hi)
2187+
r=hi;
2188+
for (l=lo+size; l<=r; l+=size)
2189+
if (compar(l, lo)<0)
2190+
lo=l;
2191+
pqsswap((unsigned char *)base, lo, size);
2192+
l=(unsigned char *)base+size;
2193+
hi-=size;
2194+
while (l<=hi) {
2195+
lo=l;
2196+
l+=size;
2197+
while (compar(l, lo)<0)
2198+
lo-=size;
2199+
lo+=size;
2200+
if (lo!=l) {
2201+
unsigned char *t=l+size;
2202+
if (u32size) {
2203+
while ((t-=sizeof(uint32_t))>=l) {
2204+
uint32_t tmp=*(uint32_t *)t;
2205+
for (r=mid=t; (mid-=size)>=lo; r=mid)
2206+
*(uint32_t *)r=*(uint32_t *)mid;
2207+
*(uint32_t *)r=tmp;
2208+
}
2209+
} else {
2210+
while (--t>=l) {
2211+
unsigned char tmp=*t;
2212+
for (r=mid=t; (mid-=size)>=lo; r=mid)
2213+
*r=*mid;
2214+
*r=tmp;
2215+
}
2216+
}
2217+
}
2218+
}
2219+
}
2220+
20252221
void psync_try_free_memory(){
20262222
sqlite3_db_release_memory(psync_db);
20272223
psync_cache_clean_all();

plibs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,8 @@ void *psync_task_get_result(psync_task_manager_t tm, int id);
326326
void psync_task_free(psync_task_manager_t tm);
327327
int psync_task_complete(void *h, void *data);
328328

329+
void psync_pqsort(void *base, size_t cnt, size_t sort_first, size_t size, int (*compar)(const void *, const void *));
330+
329331
void psync_try_free_memory();
330332

331333
int psync_debug(const char *file, const char *function, int unsigned line, int unsigned level, const char *fmt, ...) PSYNC_COLD PSYNC_FORMAT(printf, 5, 6) PSYNC_NONNULL(5);

0 commit comments

Comments
 (0)