mirror of
https://codeberg.org/redict/redict.git
synced 2025-01-22 08:08:53 -05:00
redis-cli --replica
reads dummy empty rdb instead of full snapshot (#10044)
This makes redis-cli --replica much faster and reduces COW/fork risks on server side. This commit also improves the RDB filtering via REPLCONF rdb-filter-only to support no "include" specifiers at all.
This commit is contained in:
parent
d5a3b3f5ec
commit
65a7635793
10
src/rdb.c
10
src/rdb.c
@ -1337,19 +1337,19 @@ int rdbSaveRio(int req, rio *rdb, int *error, int rdbflags, rdbSaveInfo *rsi) {
|
||||
snprintf(magic,sizeof(magic),"REDIS%04d",RDB_VERSION);
|
||||
if (rdbWriteRaw(rdb,magic,9) == -1) goto werr;
|
||||
if (rdbSaveInfoAuxFields(rdb,rdbflags,rsi) == -1) goto werr;
|
||||
if (!(req & SLAVE_REQ_RDB_FUNCTIONS_ONLY) && rdbSaveModulesAux(rdb, REDISMODULE_AUX_BEFORE_RDB) == -1) goto werr;
|
||||
if (!(req & SLAVE_REQ_RDB_EXCLUDE_DATA) && rdbSaveModulesAux(rdb, REDISMODULE_AUX_BEFORE_RDB) == -1) goto werr;
|
||||
|
||||
/* save functions */
|
||||
if (rdbSaveFunctions(rdb) == -1) goto werr;
|
||||
if (!(req & SLAVE_REQ_RDB_EXCLUDE_FUNCTIONS) && rdbSaveFunctions(rdb) == -1) goto werr;
|
||||
|
||||
/* save all databases, skip this if we're in functions-only mode */
|
||||
if (!(req & SLAVE_REQ_RDB_FUNCTIONS_ONLY)) {
|
||||
if (!(req & SLAVE_REQ_RDB_EXCLUDE_DATA)) {
|
||||
for (j = 0; j < server.dbnum; j++) {
|
||||
if (rdbSaveDb(rdb, j, rdbflags, &key_counter) == -1) goto werr;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(req & SLAVE_REQ_RDB_FUNCTIONS_ONLY) && rdbSaveModulesAux(rdb, REDISMODULE_AUX_AFTER_RDB) == -1) goto werr;
|
||||
if (!(req & SLAVE_REQ_RDB_EXCLUDE_DATA) && rdbSaveModulesAux(rdb, REDISMODULE_AUX_AFTER_RDB) == -1) goto werr;
|
||||
|
||||
/* EOF opcode */
|
||||
if (rdbSaveType(rdb,RDB_OPCODE_EOF) == -1) goto werr;
|
||||
@ -3405,7 +3405,7 @@ void saveCommand(client *c) {
|
||||
}
|
||||
rdbSaveInfo rsi, *rsiptr;
|
||||
rsiptr = rdbPopulateSaveInfo(&rsi);
|
||||
if (rdbSave(SLAVE_REQ_NONE, server.rdb_filename,rsiptr) == C_OK) {
|
||||
if (rdbSave(SLAVE_REQ_NONE,server.rdb_filename,rsiptr) == C_OK) {
|
||||
addReply(c,shared.ok);
|
||||
} else {
|
||||
addReplyErrorObject(c,shared.err);
|
||||
|
@ -8542,6 +8542,7 @@ int main(int argc, char **argv) {
|
||||
if (config.slave_mode) {
|
||||
if (cliConnect(0) == REDIS_ERR) exit(1);
|
||||
sendCapa();
|
||||
sendReplconf("rdb-filter-only", "");
|
||||
slaveMode();
|
||||
}
|
||||
|
||||
|
@ -833,11 +833,11 @@ int startBgsaveForReplication(int mincapa, int req) {
|
||||
listNode *ln;
|
||||
|
||||
/* We use a socket target if slave can handle the EOF marker and we're configured to do diskless syncs.
|
||||
* Note that in case we're creating a "filtered" RDB (functions-only) we also force socket replication
|
||||
* Note that in case we're creating a "filtered" RDB (functions-only, for example) we also force socket replication
|
||||
* to avoid overwriting the snapshot RDB file with filtered data. */
|
||||
socket_target = (server.repl_diskless_sync || (req & SLAVE_REQ_RDB_FUNCTIONS_ONLY)) && (mincapa & SLAVE_CAPA_EOF);
|
||||
socket_target = (server.repl_diskless_sync || req & SLAVE_REQ_RDB_MASK) && (mincapa & SLAVE_CAPA_EOF);
|
||||
/* `SYNC` should have failed with error if we don't support socket and require a filter, assert this here */
|
||||
serverAssert(socket_target || !(req & SLAVE_REQ_RDB_FUNCTIONS_ONLY));
|
||||
serverAssert(socket_target || !(req & SLAVE_REQ_RDB_MASK));
|
||||
|
||||
serverLog(LL_NOTICE,"Starting BGSAVE for SYNC with target: %s",
|
||||
socket_target ? "replicas sockets" : "disk");
|
||||
@ -958,7 +958,7 @@ void syncCommand(client *c) {
|
||||
/* Fail sync if slave doesn't support EOF capability but wants a filtered RDB. This is because we force filtered
|
||||
* RDB's to be generated over a socket and not through a file to avoid conflicts with the snapshot files. Forcing
|
||||
* use of a socket is handled, if needed, in `startBgsaveForReplication`. */
|
||||
if ((c->slave_req & SLAVE_REQ_RDB_FUNCTIONS_ONLY) && !(c->slave_capa & SLAVE_CAPA_EOF)) {
|
||||
if (c->slave_req & SLAVE_REQ_RDB_MASK && !(c->slave_capa & SLAVE_CAPA_EOF)) {
|
||||
addReplyError(c,"Filtered replica requires EOF capability");
|
||||
return;
|
||||
}
|
||||
@ -1124,7 +1124,8 @@ void syncCommand(client *c) {
|
||||
*
|
||||
* - rdb-filter-only <include-filters>
|
||||
* Define "include" filters for the RDB snapshot. Currently we only support
|
||||
* a single include filter: "functions". */
|
||||
* a single include filter: "functions". Passing an empty string "" will
|
||||
* result in an empty RDB. */
|
||||
void replconfCommand(client *c) {
|
||||
int j;
|
||||
|
||||
@ -1214,9 +1215,12 @@ void replconfCommand(client *c) {
|
||||
addReplyErrorFormat(c, "Missing rdb-filter-only values");
|
||||
return;
|
||||
}
|
||||
/* By default filter out all parts of the rdb */
|
||||
c->slave_req |= SLAVE_REQ_RDB_EXCLUDE_DATA;
|
||||
c->slave_req |= SLAVE_REQ_RDB_EXCLUDE_FUNCTIONS;
|
||||
for (i = 0; i < filter_count; i++) {
|
||||
if (!strcasecmp(filters[i], "functions"))
|
||||
c->slave_req |= SLAVE_REQ_RDB_FUNCTIONS_ONLY;
|
||||
c->slave_req &= ~SLAVE_REQ_RDB_EXCLUDE_FUNCTIONS;
|
||||
else {
|
||||
addReplyErrorFormat(c, "Unsupported rdb-filter-only option: %s", (char*)filters[i]);
|
||||
sdsfreesplitres(filters, filter_count);
|
||||
|
@ -1222,7 +1222,7 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
|
||||
sp->changes, (int)sp->seconds);
|
||||
rdbSaveInfo rsi, *rsiptr;
|
||||
rsiptr = rdbPopulateSaveInfo(&rsi);
|
||||
rdbSaveBackground(SLAVE_REQ_NONE, server.rdb_filename,rsiptr);
|
||||
rdbSaveBackground(SLAVE_REQ_NONE,server.rdb_filename,rsiptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1315,7 +1315,7 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
|
||||
{
|
||||
rdbSaveInfo rsi, *rsiptr;
|
||||
rsiptr = rdbPopulateSaveInfo(&rsi);
|
||||
if (rdbSaveBackground(SLAVE_REQ_NONE, server.rdb_filename,rsiptr) == C_OK)
|
||||
if (rdbSaveBackground(SLAVE_REQ_NONE,server.rdb_filename,rsiptr) == C_OK)
|
||||
server.rdb_bgsave_scheduled = 0;
|
||||
}
|
||||
|
||||
@ -3852,7 +3852,7 @@ int finishShutdown(void) {
|
||||
/* Snapshotting. Perform a SYNC SAVE and exit */
|
||||
rdbSaveInfo rsi, *rsiptr;
|
||||
rsiptr = rdbPopulateSaveInfo(&rsi);
|
||||
if (rdbSave(SLAVE_REQ_NONE, server.rdb_filename,rsiptr) != C_OK) {
|
||||
if (rdbSave(SLAVE_REQ_NONE,server.rdb_filename,rsiptr) != C_OK) {
|
||||
/* Ooops.. error saving! The best we can do is to continue
|
||||
* operating. Note that if there was a background saving process,
|
||||
* in the next cron() Redis will be notified that the background
|
||||
|
@ -387,7 +387,10 @@ typedef enum {
|
||||
|
||||
/* Slave requirements */
|
||||
#define SLAVE_REQ_NONE 0
|
||||
#define SLAVE_REQ_RDB_FUNCTIONS_ONLY (1 << 0)
|
||||
#define SLAVE_REQ_RDB_EXCLUDE_DATA (1 << 0) /* Exclude data from RDB */
|
||||
#define SLAVE_REQ_RDB_EXCLUDE_FUNCTIONS (1 << 1) /* Exclude functions from RDB */
|
||||
/* Mask of all bits in the slave requirements bitfield that represent non-standard (filtered) RDB requirements */
|
||||
#define SLAVE_REQ_RDB_MASK (SLAVE_REQ_RDB_EXCLUDE_DATA | SLAVE_REQ_RDB_EXCLUDE_FUNCTIONS)
|
||||
|
||||
/* Synchronous read timeout - slave side */
|
||||
#define CONFIG_REPL_SYNCIO_TIMEOUT 5
|
||||
|
Loading…
Reference in New Issue
Block a user