This function is called when the user modifies the replication backlog * size at runtime. It is up to the function to both update the * g_pserver->repl_backlog_size and to resize the buffer and setup it so that * it contains the same data as the previous one (possibly less data, but * the most recent bytes, or the same data and more free space in case the * buffer is enlarged). */
| 262 | * the most recent bytes, or the same data and more free space in case the |
| 263 | * buffer is enlarged). */ |
| 264 | void resizeReplicationBacklog(long long newsize) { |
| 265 | if (newsize < CONFIG_REPL_BACKLOG_MIN_SIZE) |
| 266 | newsize = CONFIG_REPL_BACKLOG_MIN_SIZE; |
| 267 | if (g_pserver->repl_backlog_size == newsize) return; |
| 268 | |
| 269 | if (g_pserver->repl_backlog != NULL) { |
| 270 | std::unique_lock<fastlock> repl_backlog_lock(g_pserver->repl_backlog_lock); |
| 271 | /* What we actually do is to flush the old buffer and realloc a new |
| 272 | * empty one. It will refill with new data incrementally. |
| 273 | * The reason is that copying a few gigabytes adds latency and even |
| 274 | * worse often we need to alloc additional space before freeing the |
| 275 | * old buffer. */ |
| 276 | |
| 277 | /* get the critical client size, i.e. the size of the data unflushed to clients */ |
| 278 | long long earliest_off = g_pserver->repl_lowest_off.load(); |
| 279 | |
| 280 | if (earliest_off != -1) { |
| 281 | char *backlog = nullptr; |
| 282 | newsize = std::max(newsize, g_pserver->master_repl_offset - earliest_off); |
| 283 | |
| 284 | if (cserver.repl_backlog_disk_size != 0) { |
| 285 | if (newsize > g_pserver->repl_backlog_config_size || cserver.force_backlog_disk) { |
| 286 | if (g_pserver->repl_backlog == g_pserver->repl_backlog_disk) |
| 287 | return; // Can't do anything more |
| 288 | serverLog(LL_NOTICE, "Switching to disk backed replication backlog due to exceeding memory limits"); |
| 289 | backlog = g_pserver->repl_backlog_disk; |
| 290 | newsize = cserver.repl_backlog_disk_size; |
| 291 | } |
| 292 | } |
| 293 | |
| 294 | // We need to keep critical data so we can't shrink less than the hot data in the buffer |
| 295 | if (backlog == nullptr) |
| 296 | backlog = (char*)zmalloc(newsize); |
| 297 | g_pserver->repl_backlog_histlen = g_pserver->master_repl_offset - earliest_off; |
| 298 | long long earliest_idx = getReplIndexFromOffset(earliest_off); |
| 299 | |
| 300 | if (g_pserver->repl_backlog_idx >= earliest_idx) { |
| 301 | auto cbActiveBacklog = g_pserver->repl_backlog_idx - earliest_idx; |
| 302 | memcpy(backlog, g_pserver->repl_backlog + earliest_idx, cbActiveBacklog); |
| 303 | serverAssert(g_pserver->repl_backlog_histlen == cbActiveBacklog); |
| 304 | } else { |
| 305 | auto cbPhase1 = g_pserver->repl_backlog_size - earliest_idx; |
| 306 | memcpy(backlog, g_pserver->repl_backlog + earliest_idx, cbPhase1); |
| 307 | memcpy(backlog + cbPhase1, g_pserver->repl_backlog, g_pserver->repl_backlog_idx); |
| 308 | auto cbActiveBacklog = cbPhase1 + g_pserver->repl_backlog_idx; |
| 309 | serverAssert(g_pserver->repl_backlog_histlen == cbActiveBacklog); |
| 310 | } |
| 311 | if (g_pserver->repl_backlog != g_pserver->repl_backlog_disk) |
| 312 | zfree(g_pserver->repl_backlog); |
| 313 | else |
| 314 | serverLog(LL_NOTICE, "Returning to memory backed replication backlog"); |
| 315 | g_pserver->repl_backlog = backlog; |
| 316 | g_pserver->repl_backlog_idx = g_pserver->repl_backlog_histlen; |
| 317 | if (g_pserver->repl_batch_idxStart >= 0) { |
| 318 | g_pserver->repl_batch_idxStart -= earliest_idx; |
| 319 | if (g_pserver->repl_batch_idxStart < 0) |
| 320 | g_pserver->repl_batch_idxStart += g_pserver->repl_backlog_size; |
| 321 | } |
no test coverage detected