diff --git a/src/rdb.c b/src/rdb.c index ee14fd12c..a8172a865 100644 --- a/src/rdb.c +++ b/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); diff --git a/src/redis-cli.c b/src/redis-cli.c index 0a19c025d..9ec5ecfa9 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -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(); } diff --git a/src/replication.c b/src/replication.c index 3bdd1cc89..a0a19f36d 100644 --- a/src/replication.c +++ b/src/replication.c @@ -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 * 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); diff --git a/src/server.c b/src/server.c index 571631381..96e293a24 100644 --- a/src/server.c +++ b/src/server.c @@ -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 diff --git a/src/server.h b/src/server.h index 959a8c645..3706cca23 100644 --- a/src/server.h +++ b/src/server.h @@ -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