Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
a67957ed
"app/vscode:/vscode.git/clone" did not exist on "6efbf13eae052401d96aea682fc9d64a6f1794db"
Commit
a67957ed
authored
Nov 08, 2022
by
Viktor Söderqvist
Browse files
Let active expire cycle use dictScan instead of messing with internals
parent
c84248b5
Changes
1
Show whitespace changes
Inline
Side-by-side
src/expire.c
View file @
a67957ed
...
...
@@ -110,6 +110,33 @@ int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
#define ACTIVE_EXPIRE_CYCLE_ACCEPTABLE_STALE 10
/* % of stale keys after which
we do extra efforts. */
/* Data used by the expire dict scan callback. */
typedef
struct
{
redisDb
*
db
;
long
long
now
;
unsigned
long
sampled
;
/* num keys checked */
unsigned
long
expired
;
/* num keys expired */
long
long
ttl_sum
;
/* sum of ttl for key with ttl not yet expired */
int
ttl_samples
;
/* num keys with ttl not yet expired */
}
expireScanData
;
void
expireScanCallback
(
void
*
privdata
,
const
dictEntry
*
const_de
)
{
dictEntry
*
de
=
(
dictEntry
*
)
const_de
;
expireScanData
*
data
=
privdata
;
long
long
ttl
=
dictGetSignedIntegerVal
(
de
)
-
data
->
now
;
if
(
activeExpireCycleTryExpire
(
data
->
db
,
de
,
data
->
now
))
{
data
->
expired
++
;
/* Propagate the DEL command */
postExecutionUnitOperations
();
}
if
(
ttl
>
0
)
{
/* We want the average TTL of keys yet not expired. */
data
->
ttl_sum
+=
ttl
;
data
->
ttl_samples
++
;
}
data
->
sampled
++
;
}
void
activeExpireCycle
(
int
type
)
{
/* Adjust the running parameters according to the configured expire
* effort. The default effort is 1, and the maximum configurable effort
...
...
@@ -186,10 +213,11 @@ void activeExpireCycle(int type) {
serverAssert
(
server
.
also_propagate
.
numops
==
0
);
for
(
j
=
0
;
j
<
dbs_per_call
&&
timelimit_exit
==
0
;
j
++
)
{
/*
Expired and checked in a single loop
. */
unsigned
long
expired
,
sampled
;
/*
Scan callback data including expired and checked count per iteration
. */
expireScanData
data
;
redisDb
*
db
=
server
.
db
+
(
current_db
%
server
.
dbnum
);
data
.
db
=
db
;
/* Increment the DB now so we are sure if we run out of time
* in the current DB we'll restart from the next. This allows to
...
...
@@ -202,8 +230,6 @@ void activeExpireCycle(int type) {
* is not fixed, but depends on the Redis configured "expire effort". */
do
{
unsigned
long
num
,
slots
;
long
long
now
,
ttl_sum
;
int
ttl_samples
;
iteration
++
;
/* If there is nothing to expire try next DB ASAP. */
...
...
@@ -212,7 +238,7 @@ void activeExpireCycle(int type) {
break
;
}
slots
=
dictSlots
(
db
->
expires
);
now
=
mstime
();
data
.
now
=
mstime
();
/* When there are less than 1% filled slots, sampling the key
* space is expensive, so stop here waiting for better times...
...
...
@@ -220,12 +246,12 @@ void activeExpireCycle(int type) {
if
(
slots
>
DICT_HT_INITIAL_SIZE
&&
(
num
*
100
/
slots
<
1
))
break
;
/* The main collection cycle. S
ample random
keys among keys
/* The main collection cycle. S
can through
keys among keys
* with an expire set, checking for expired ones. */
expir
ed
=
0
;
sampl
ed
=
0
;
ttl_sum
=
0
;
ttl_samples
=
0
;
data
.
sampl
ed
=
0
;
data
.
expir
ed
=
0
;
data
.
ttl_sum
=
0
;
data
.
ttl_samples
=
0
;
if
(
num
>
config_keys_per_loop
)
num
=
config_keys_per_loop
;
...
...
@@ -243,46 +269,17 @@ void activeExpireCycle(int type) {
long
max_buckets
=
num
*
20
;
long
checked_buckets
=
0
;
while
(
sampled
<
num
&&
checked_buckets
<
max_buckets
)
{
for
(
int
table
=
0
;
table
<
2
;
table
++
)
{
if
(
table
==
1
&&
!
dictIsRehashing
(
db
->
expires
))
break
;
unsigned
long
idx
=
db
->
expires_cursor
;
idx
&=
DICTHT_SIZE_MASK
(
db
->
expires
->
ht_size_exp
[
table
]);
dictEntry
*
de
=
db
->
expires
->
ht_table
[
table
][
idx
];
long
long
ttl
;
/* Scan the current bucket of the current table. */
while
(
data
.
sampled
<
num
&&
checked_buckets
<
max_buckets
)
{
db
->
expires_cursor
=
dictScan
(
db
->
expires
,
db
->
expires_cursor
,
expireScanCallback
,
NULL
,
&
data
);
checked_buckets
++
;
while
(
de
)
{
/* Get the next entry now since this entry may get
* deleted. */
dictEntry
*
e
=
de
;
de
=
dictGetNext
(
de
);
ttl
=
dictGetSignedIntegerVal
(
e
)
-
now
;
if
(
activeExpireCycleTryExpire
(
db
,
e
,
now
))
{
expired
++
;
/* Propagate the DEL command */
postExecutionUnitOperations
();
}
if
(
ttl
>
0
)
{
/* We want the average TTL of keys yet
* not expired. */
ttl_sum
+=
ttl
;
ttl_samples
++
;
}
sampled
++
;
}
}
db
->
expires_cursor
++
;
}
total_expired
+=
expired
;
total_sampled
+=
sampled
;
total_expired
+=
data
.
expired
;
total_sampled
+=
data
.
sampled
;
/* Update the average TTL stats for this database. */
if
(
ttl_samples
)
{
long
long
avg_ttl
=
ttl_sum
/
ttl_samples
;
if
(
data
.
ttl_samples
)
{
long
long
avg_ttl
=
data
.
ttl_sum
/
data
.
ttl_samples
;
/* Do a simple running average with a few samples.
* We just use the current estimate with a weight of 2%
...
...
@@ -305,8 +302,8 @@ void activeExpireCycle(int type) {
/* We don't repeat the cycle for the current database if there are
* an acceptable amount of stale keys (logically expired but yet
* not reclaimed). */
}
while
(
sampled
==
0
||
(
expired
*
100
/
sampled
)
>
config_cycle_acceptable_stale
);
}
while
(
data
.
sampled
==
0
||
(
data
.
expired
*
100
/
data
.
sampled
)
>
config_cycle_acceptable_stale
);
}
elapsed
=
ustime
()
-
start
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment