Save a key-value pair, with expire time, type, key, value. * On error -1 is returned. * On success if the key was actually saved 1 is returned. */
| 1131 | * On error -1 is returned. |
| 1132 | * On success if the key was actually saved 1 is returned. */ |
| 1133 | int rdbSaveKeyValuePair(rio *rdb, robj_roptr key, robj_roptr val, const expireEntry *pexpire) { |
| 1134 | int savelru = g_pserver->maxmemory_policy & MAXMEMORY_FLAG_LRU; |
| 1135 | int savelfu = g_pserver->maxmemory_policy & MAXMEMORY_FLAG_LFU; |
| 1136 | |
| 1137 | /* Save the expire time */ |
| 1138 | long long expiretime = INVALID_EXPIRE; |
| 1139 | if (pexpire != nullptr && pexpire->FGetPrimaryExpire(&expiretime)) { |
| 1140 | if (rdbSaveType(rdb,RDB_OPCODE_EXPIRETIME_MS) == -1) return -1; |
| 1141 | if (rdbSaveMillisecondTime(rdb,expiretime) == -1) return -1; |
| 1142 | } |
| 1143 | |
| 1144 | /* Save the LRU info. */ |
| 1145 | if (savelru) { |
| 1146 | uint64_t idletime = estimateObjectIdleTime(val); |
| 1147 | idletime /= 1000; /* Using seconds is enough and requires less space.*/ |
| 1148 | if (rdbSaveType(rdb,RDB_OPCODE_IDLE) == -1) return -1; |
| 1149 | if (rdbSaveLen(rdb,idletime) == -1) return -1; |
| 1150 | } |
| 1151 | |
| 1152 | /* Save the LFU info. */ |
| 1153 | if (savelfu) { |
| 1154 | uint8_t buf[1]; |
| 1155 | buf[0] = LFUDecrAndReturn(val); |
| 1156 | /* We can encode this in exactly two bytes: the opcode and an 8 |
| 1157 | * bit counter, since the frequency is logarithmic with a 0-255 range. |
| 1158 | * Note that we do not store the halving time because to reset it |
| 1159 | * a single time when loading does not affect the frequency much. */ |
| 1160 | if (rdbSaveType(rdb,RDB_OPCODE_FREQ) == -1) return -1; |
| 1161 | if (rdbWriteRaw(rdb,buf,1) == -1) return -1; |
| 1162 | } |
| 1163 | |
| 1164 | char szT[32]; |
| 1165 | if (g_pserver->fActiveReplica) { |
| 1166 | snprintf(szT, sizeof(szT), "%" PRIu64, mvccFromObj(val)); |
| 1167 | if (rdbSaveAuxFieldStrStr(rdb,"mvcc-tstamp", szT) == -1) return -1; |
| 1168 | } |
| 1169 | |
| 1170 | /* Save type, key, value */ |
| 1171 | if (rdbSaveObjectType(rdb,val) == -1) return -1; |
| 1172 | if (rdbSaveStringObject(rdb,key) == -1) return -1; |
| 1173 | if (rdbSaveObject(rdb,val,key) == -1) return -1; |
| 1174 | |
| 1175 | /* Delay return if required (for testing) */ |
| 1176 | if (serverTL->getRdbKeySaveDelay()) { |
| 1177 | int sleepTime = serverTL->getRdbKeySaveDelay(); |
| 1178 | while (!g_pserver->rdbThreadVars.fRdbThreadCancel && sleepTime > 0) { |
| 1179 | int sleepThisTime = std::min(100, sleepTime); |
| 1180 | debugDelay(sleepThisTime); |
| 1181 | sleepTime -= sleepThisTime; |
| 1182 | } |
| 1183 | } |
| 1184 | |
| 1185 | /* Save expire entry after as it will apply to the previously loaded key */ |
| 1186 | /* This is because we update the expire datastructure directly without buffering */ |
| 1187 | if (pexpire != nullptr) |
| 1188 | { |
| 1189 | for (auto itr : *pexpire) |
| 1190 | { |
no test coverage detected