Lock the cluster config using flock(), and leaks the file descriptor used to * acquire the lock so that the file will be locked forever. * * This works because we always update nodes.conf with a new version * in-place, reopening the file, and writing to it in place (later adjusting * the length with ftruncate()). * * On success C_OK is returned, otherwise an error is logged and * the funct
| 410 | * On success C_OK is returned, otherwise an error is logged and |
| 411 | * the function returns C_ERR to signal a lock was not acquired. */ |
| 412 | int clusterLockConfig(char *filename) { |
| 413 | /* flock() does not exist on Solaris |
| 414 | * and a fcntl-based solution won't help, as we constantly re-open that file, |
| 415 | * which will release _all_ locks anyway |
| 416 | */ |
| 417 | #if !defined(__sun) |
| 418 | /* To lock it, we need to open the file in a way it is created if |
| 419 | * it does not exist, otherwise there is a race condition with other |
| 420 | * processes. */ |
| 421 | int fd = open(filename,O_WRONLY|O_CREAT|O_CLOEXEC,0644); |
| 422 | if (fd == -1) { |
| 423 | serverLog(LL_WARNING, |
| 424 | "Can't open %s in order to acquire a lock: %s", |
| 425 | filename, strerror(errno)); |
| 426 | return C_ERR; |
| 427 | } |
| 428 | |
| 429 | if (flock(fd,LOCK_EX|LOCK_NB) == -1) { |
| 430 | if (errno == EWOULDBLOCK) { |
| 431 | serverLog(LL_WARNING, |
| 432 | "Sorry, the cluster configuration file %s is already used " |
| 433 | "by a different KeyDB Cluster node. Please make sure that " |
| 434 | "different nodes use different cluster configuration " |
| 435 | "files.", filename); |
| 436 | } else { |
| 437 | serverLog(LL_WARNING, |
| 438 | "Impossible to lock %s: %s", filename, strerror(errno)); |
| 439 | } |
| 440 | close(fd); |
| 441 | return C_ERR; |
| 442 | } |
| 443 | /* Lock acquired: leak the 'fd' by not closing it, so that we'll retain the |
| 444 | * lock to the file as long as the process exists. |
| 445 | * |
| 446 | * After fork, the child process will get the fd opened by the parent process, |
| 447 | * we need save `fd` to `cluster_config_file_lock_fd`, so that in redisFork(), |
| 448 | * it will be closed in the child process. |
| 449 | * If it is not closed, when the main process is killed -9, but the child process |
| 450 | * (redis-aof-rewrite) is still alive, the fd(lock) will still be held by the |
| 451 | * child process, and the main process will fail to get lock, means fail to start. */ |
| 452 | g_pserver->cluster_config_file_lock_fd = fd; |
| 453 | #endif /* __sun */ |
| 454 | |
| 455 | return C_OK; |
| 456 | } |
| 457 | |
| 458 | /* Derives our ports to be announced in the cluster bus. */ |
| 459 | void deriveAnnouncedPorts(int *announced_port, int *announced_pport, |
no test coverage detected