Produces a dump of the database in RDB format sending it to the specified * Redis I/O channel. On success C_OK is returned, otherwise C_ERR * is returned and part of the output, or all the output, can be * missing because of I/O errors. * * When the function returns C_ERR and if 'error' is not NULL, the * integer pointed by 'error' is set to the value of errno just after the I/O * error. */
| 1312 | * integer pointed by 'error' is set to the value of errno just after the I/O |
| 1313 | * error. */ |
| 1314 | int rdbSaveRio(rio *rdb, const redisDbPersistentDataSnapshot **rgpdb, int *error, int rdbflags, rdbSaveInfo *rsi) { |
| 1315 | dictEntry *de; |
| 1316 | dictIterator *di = NULL; |
| 1317 | char magic[10]; |
| 1318 | uint64_t cksum; |
| 1319 | size_t processed = 0; |
| 1320 | int j; |
| 1321 | long key_count = 0; |
| 1322 | long long info_updated_time = 0; |
| 1323 | const char *pname = (rdbflags & RDBFLAGS_AOF_PREAMBLE) ? "AOF rewrite" : "RDB"; |
| 1324 | |
| 1325 | if (g_pserver->rdb_checksum) |
| 1326 | rdb->update_cksum = rioGenericUpdateChecksum; |
| 1327 | snprintf(magic,sizeof(magic),"REDIS%04d",RDB_VERSION); |
| 1328 | if (rdbWriteRaw(rdb,magic,9) == -1) goto werr; |
| 1329 | if (rdbSaveInfoAuxFields(rdb,rdbflags,rsi) == -1) goto werr; |
| 1330 | if (rdbSaveModulesAux(rdb, REDISMODULE_AUX_BEFORE_RDB) == -1) goto werr; |
| 1331 | |
| 1332 | for (j = 0; j < cserver.dbnum; j++) { |
| 1333 | const redisDbPersistentDataSnapshot *db = rgpdb != nullptr ? rgpdb[j] : g_pserver->db[j]; |
| 1334 | if (db->size() == 0) continue; |
| 1335 | |
| 1336 | /* Write the SELECT DB opcode */ |
| 1337 | if (rdbSaveType(rdb,RDB_OPCODE_SELECTDB) == -1) goto werr; |
| 1338 | if (rdbSaveLen(rdb,j) == -1) goto werr; |
| 1339 | |
| 1340 | /* Write the RESIZE DB opcode. */ |
| 1341 | uint64_t db_size, expires_size; |
| 1342 | db_size = db->size(); |
| 1343 | expires_size = db->expireSize(); |
| 1344 | if (rdbSaveType(rdb,RDB_OPCODE_RESIZEDB) == -1) goto werr; |
| 1345 | if (rdbSaveLen(rdb,db_size) == -1) goto werr; |
| 1346 | if (rdbSaveLen(rdb,expires_size) == -1) goto werr; |
| 1347 | |
| 1348 | /* Iterate this DB writing every entry */ |
| 1349 | size_t ckeysExpired = 0; |
| 1350 | bool fSavedAll = db->iterate_threadsafe([&](const char *keystr, robj_roptr o)->bool { |
| 1351 | if (o->FExpires()) |
| 1352 | ++ckeysExpired; |
| 1353 | |
| 1354 | if (!saveKey(rdb, rdbflags, &processed, keystr, o)) |
| 1355 | return false; |
| 1356 | |
| 1357 | /* Update child info every 1 second (approximately). |
| 1358 | * in order to avoid calling mstime() on each iteration, we will |
| 1359 | * check the diff every 1024 keys */ |
| 1360 | if ((key_count++ & 1023) == 0) { |
| 1361 | long long now = mstime(); |
| 1362 | if (now - info_updated_time >= 1000) { |
| 1363 | sendChildInfo(CHILD_INFO_TYPE_CURRENT_INFO, key_count, pname); |
| 1364 | info_updated_time = now; |
| 1365 | } |
| 1366 | } |
| 1367 | |
| 1368 | return !g_pserver->rdbThreadVars.fRdbThreadCancel; |
| 1369 | }); |
| 1370 | if (!fSavedAll) |
| 1371 | goto werr; |
no test coverage detected