Swap two databases at runtime so that all clients will magically see * the new database even if already connected. Note that the client * structure c->db points to a given DB, so we need to be smarter and * swap the underlying referenced structures, otherwise we would need * to fix all the references to the Redis DB structure. * * Returns C_ERR if at least one of the DB ids are out of range,
| 1325 | * Returns C_ERR if at least one of the DB ids are out of range, otherwise |
| 1326 | * C_OK is returned. */ |
| 1327 | int dbSwapDatabases(int id1, int id2) { |
| 1328 | if (id1 < 0 || id1 >= server.dbnum || |
| 1329 | id2 < 0 || id2 >= server.dbnum) return C_ERR; |
| 1330 | if (id1 == id2) return C_OK; |
| 1331 | redisDb aux = server.db[id1]; |
| 1332 | redisDb *db1 = &server.db[id1], *db2 = &server.db[id2]; |
| 1333 | |
| 1334 | /* Swap hash tables. Note that we don't swap blocking_keys, |
| 1335 | * ready_keys and watched_keys, since we want clients to |
| 1336 | * remain in the same DB they were. */ |
| 1337 | db1->dict = db2->dict; |
| 1338 | db1->expires = db2->expires; |
| 1339 | db1->avg_ttl = db2->avg_ttl; |
| 1340 | db1->expires_cursor = db2->expires_cursor; |
| 1341 | |
| 1342 | db2->dict = aux.dict; |
| 1343 | db2->expires = aux.expires; |
| 1344 | db2->avg_ttl = aux.avg_ttl; |
| 1345 | db2->expires_cursor = aux.expires_cursor; |
| 1346 | |
| 1347 | /* Now we need to handle clients blocked on lists: as an effect |
| 1348 | * of swapping the two DBs, a client that was waiting for list |
| 1349 | * X in a given DB, may now actually be unblocked if X happens |
| 1350 | * to exist in the new version of the DB, after the swap. |
| 1351 | * |
| 1352 | * However normally we only do this check for efficiency reasons |
| 1353 | * in dbAdd() when a list is created. So here we need to rescan |
| 1354 | * the list of clients blocked on lists and signal lists as ready |
| 1355 | * if needed. |
| 1356 | * |
| 1357 | * Also the swapdb should make transaction fail if there is any |
| 1358 | * client watching keys */ |
| 1359 | scanDatabaseForReadyLists(db1); |
| 1360 | touchAllWatchedKeysInDb(db1, db2); |
| 1361 | scanDatabaseForReadyLists(db2); |
| 1362 | touchAllWatchedKeysInDb(db2, db1); |
| 1363 | return C_OK; |
| 1364 | } |
| 1365 | |
| 1366 | /* SWAPDB db1 db2 */ |
| 1367 | void swapdbCommand(client *c) { |
no test coverage detected