1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2024-12-12 10:04:14 +02:00

Add lock module initialization.

Each call to lockAcquireP() passed enough information to initialize the lock system. This was somewhat inefficient and as locks become more complicated it will lead to more code duplication. Since a process can only take one type of lock it makes sense to do most of the initialization up front.

Also reduce the log level of lockRelease() since it is only called at exit and the lock will be released in any case.
This commit is contained in:
David Steele 2023-03-25 14:07:31 +07:00
parent f1caecc4ff
commit 8ff956ad7e
20 changed files with 197 additions and 133 deletions

View File

@ -463,9 +463,7 @@ HRN_FORK_BEGIN()
{
HRN_FORK_CHILD_BEGIN()
{
TEST_RESULT_INT_NE(
lockAcquireP(cfgOptionStr(cfgOptLockPath), STRDEF("stanza1"), STRDEF("999-ffffffff"), lockTypeBackup), -1,
"create backup/expire lock");
TEST_RESULT_INT_NE(lockAcquireP(), -1, "create backup/expire lock");
// Notify parent that lock has been acquired
HRN_FORK_CHILD_NOTIFY_PUT();

View File

@ -530,9 +530,7 @@ HRN_FORK_BEGIN()
{
HRN_FORK_CHILD_BEGIN()
{
TEST_RESULT_INT_NE(
lockAcquireP(cfgOptionStr(cfgOptLockPath), STRDEF("stanza1"), STRDEF("999-ffffffff"), lockTypeBackup), -1,
"create backup/expire lock");
TEST_RESULT_INT_NE(lockAcquireP(), -1, "create backup/expire lock");
// Notify parent that lock has been acquired
HRN_FORK_CHILD_NOTIFY_PUT();

View File

@ -718,10 +718,7 @@ cmdArchiveGet(void)
// If the WAL segment has not already been found then start the async process to get it. There's no point in
// forking the async process off more than once so track that as well. Use an archive lock to prevent forking if
// the async process was launched by another process.
if (!forked && (!found || !queueFull) &&
lockAcquireP(
cfgOptionStr(cfgOptLockPath), cfgOptionStr(cfgOptStanza), cfgOptionStr(cfgOptExecId), cfgLockType(),
.returnOnNoLock = true))
if (!forked && (!found || !queueFull) && lockAcquireP(.returnOnNoLock = true))
{
// Get control info
PgControl pgControl = pgControlFromFile(storagePg(), cfgOptionStrNull(cfgOptPgVersionForce));

View File

@ -361,10 +361,7 @@ cmdArchivePush(void)
// If the WAL segment has not already been pushed then start the async process to push it. There's no point in
// forking the async process off more than once so track that as well. Use an archive lock to prevent more than
// one async process being launched.
if (!pushed && !forked &&
lockAcquireP(
cfgOptionStr(cfgOptLockPath), cfgOptionStr(cfgOptStanza), cfgOptionStr(cfgOptExecId), cfgLockType(),
.returnOnNoLock = true))
if (!pushed && !forked && lockAcquireP(.returnOnNoLock = true))
{
// The async process should not output on the console at all
KeyValue *optionReplace = kvNew();

View File

@ -77,8 +77,7 @@ cmdRemote(ProtocolServer *const server)
lockStopTest();
// Acquire the lock
lockAcquireP(
cfgOptionStr(cfgOptLockPath), cfgOptionStr(cfgOptStanza), cfgOptionStr(cfgOptExecId), cfgLockType());
lockAcquireP();
}
}

View File

@ -51,18 +51,48 @@ Mem context and local variables
static struct LockLocal
{
MemContext *memContext; // Mem context for locks
LockType held; // Current lock type held
const String *path; // Lock path
const String *execId; // Process exec id
const String *stanza; // Stanza
LockType type; // Lock type
bool held; // Is the lock being held?
struct
{
String *name; // Name of lock file
int fd; // File descriptor for lock file
} file[lockTypeAll];
} lockLocal =
} lockLocal;
/**********************************************************************************************************************************/
FN_EXTERN void
lockInit(const String *const path, const String *const execId, const String *const stanza, const LockType type)
{
.held = lockTypeNone,
};
FUNCTION_LOG_BEGIN(logLevelDebug);
FUNCTION_LOG_PARAM(STRING, path);
FUNCTION_LOG_PARAM(STRING, execId);
FUNCTION_LOG_PARAM(ENUM, type);
FUNCTION_LOG_END();
ASSERT(lockLocal.memContext == NULL);
// Allocate a mem context to hold lock info
MEM_CONTEXT_BEGIN(memContextTop())
{
MEM_CONTEXT_NEW_BEGIN(Lock, .childQty = MEM_CONTEXT_QTY_MAX)
{
lockLocal.memContext = MEM_CONTEXT_NEW();
lockLocal.path = strDup(path);
lockLocal.execId = strDup(execId);
lockLocal.stanza = strDup(stanza);
lockLocal.type = type;
}
MEM_CONTEXT_NEW_END();
}
MEM_CONTEXT_END();
FUNCTION_LOG_RETURN_VOID();
}
/**********************************************************************************************************************************/
FN_EXTERN String *
@ -257,7 +287,7 @@ lockWriteData(const LockType lockType, const LockWriteDataParam param)
jsonWriteObjectEnd(json);
if (lockType == lockTypeBackup && lockLocal.held != lockTypeNone)
if (lockType == lockTypeBackup && lockLocal.held)
{
// Seek to beginning of backup lock file
THROW_ON_SYS_ERROR_FMT(
@ -391,59 +421,34 @@ lockAcquireFile(const String *const lockFile, const TimeMSec lockTimeout, const
}
FN_EXTERN bool
lockAcquire(
const String *const lockPath, const String *const stanza, const String *const execId, const LockType lockType,
const LockAcquireParam param)
lockAcquire(const LockAcquireParam param)
{
FUNCTION_LOG_BEGIN(logLevelDebug);
FUNCTION_LOG_PARAM(STRING, lockPath);
FUNCTION_LOG_PARAM(STRING, stanza);
FUNCTION_LOG_PARAM(STRING, execId);
FUNCTION_LOG_PARAM(ENUM, lockType);
FUNCTION_LOG_PARAM(TIMEMSEC, param.timeout);
FUNCTION_LOG_PARAM(BOOL, param.returnOnNoLock);
FUNCTION_LOG_END();
ASSERT(lockPath != NULL);
ASSERT(stanza != NULL);
ASSERT(execId != NULL);
ASSERT(lockLocal.memContext != NULL);
bool result = true;
// Don't allow failures when locking more than one file. This makes cleanup difficult and there are no known use cases.
ASSERT(!param.returnOnNoLock || lockType != lockTypeAll);
ASSERT(!param.returnOnNoLock || lockLocal.type != lockTypeAll);
// Don't allow another lock if one is already held
if (lockLocal.held != lockTypeNone)
if (lockLocal.held)
THROW(AssertError, "lock is already held by this process");
// Allocate a mem context to hold lock filenames if one does not already exist
if (lockLocal.memContext == NULL)
{
MEM_CONTEXT_BEGIN(memContextTop())
{
MEM_CONTEXT_NEW_BEGIN(Lock, .childQty = MEM_CONTEXT_QTY_MAX)
{
lockLocal.memContext = MEM_CONTEXT_NEW();
lockLocal.execId = strDup(execId);
}
MEM_CONTEXT_NEW_END();
}
MEM_CONTEXT_END();
}
// Exec id should never change
ASSERT(strEq(execId, lockLocal.execId));
// Lock files
LockType lockMin = lockType == lockTypeAll ? lockTypeArchive : lockType;
LockType lockMax = lockType == lockTypeAll ? (lockTypeAll - 1) : lockType;
LockType lockMin = lockLocal.type == lockTypeAll ? lockTypeArchive : lockLocal.type;
LockType lockMax = lockLocal.type == lockTypeAll ? (lockTypeAll - 1) : lockLocal.type;
for (LockType lockIdx = lockMin; lockIdx <= lockMax; lockIdx++)
{
MEM_CONTEXT_BEGIN(lockLocal.memContext)
{
lockLocal.file[lockIdx].name = strNewFmt("%s/%s", strZ(lockPath), strZ(lockFileName(stanza, lockIdx)));
strFree(lockLocal.file[lockIdx].name);
lockLocal.file[lockIdx].name = strNewFmt("%s/%s", strZ(lockLocal.path), strZ(lockFileName(lockLocal.stanza, lockIdx)));
}
MEM_CONTEXT_END();
@ -451,10 +456,8 @@ lockAcquire(
if (lockLocal.file[lockIdx].fd == -1)
{
// Free the lock context and reset lock data
memContextFree(lockLocal.memContext);
lockLocal = (struct LockLocal){.held = lockTypeNone};
// Free the lock
lockLocal.held = false;
result = false;
break;
}
@ -464,7 +467,7 @@ lockAcquire(
}
if (result)
lockLocal.held = lockType;
lockLocal.held = true;
FUNCTION_LOG_RETURN(BOOL, result);
}
@ -497,13 +500,13 @@ lockReleaseFile(const int lockFd, const String *const lockFile)
FN_EXTERN bool
lockRelease(bool failOnNoLock)
{
FUNCTION_LOG_BEGIN(logLevelDebug);
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(BOOL, failOnNoLock);
FUNCTION_LOG_END();
bool result = false;
if (lockLocal.held == lockTypeNone)
if (!lockLocal.held)
{
if (failOnNoLock)
THROW(AssertError, "no lock is held by this process");
@ -511,8 +514,8 @@ lockRelease(bool failOnNoLock)
else
{
// Release locks
LockType lockMin = lockLocal.held == lockTypeAll ? lockTypeArchive : lockLocal.held;
LockType lockMax = lockLocal.held == lockTypeAll ? (lockTypeAll - 1) : lockLocal.held;
LockType lockMin = lockLocal.type == lockTypeAll ? lockTypeArchive : lockLocal.type;
LockType lockMax = lockLocal.type == lockTypeAll ? (lockTypeAll - 1) : lockLocal.type;
for (LockType lockIdx = lockMin; lockIdx <= lockMax; lockIdx++)
{
@ -520,10 +523,8 @@ lockRelease(bool failOnNoLock)
lockReleaseFile(lockLocal.file[lockIdx].fd, lockLocal.file[lockIdx].name);
}
// Free the lock context and reset lock data
memContextFree(lockLocal.memContext);
lockLocal = (struct LockLocal){.held = lockTypeNone};
// Free the lock context
lockLocal.held = false;
result = true;
}

View File

@ -37,6 +37,9 @@ Constants
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
// Initialize lock module
FN_EXTERN void lockInit(const String *path, const String *execId, const String *stanza, LockType type);
// Acquire a lock type. This will involve locking one or more files on disk depending on the lock type. Most operations only take a
// single lock (archive or backup), but the stanza commands all need to lock both.
typedef struct LockAcquireParam
@ -46,11 +49,10 @@ typedef struct LockAcquireParam
bool returnOnNoLock; // Return when no lock acquired (rather than throw an error)
} LockAcquireParam;
#define lockAcquireP(lockPath, stanza, execId, lockType, ...) \
lockAcquire(lockPath, stanza, execId, lockType, (LockAcquireParam) {VAR_PARAM_INIT, __VA_ARGS__})
#define lockAcquireP(...) \
lockAcquire((LockAcquireParam) {VAR_PARAM_INIT, __VA_ARGS__})
FN_EXTERN bool lockAcquire(
const String *lockPath, const String *stanza, const String *execId, LockType lockType, LockAcquireParam param);
FN_EXTERN bool lockAcquire(LockAcquireParam param);
// Release a lock
FN_EXTERN bool lockRelease(bool failOnNoLock);

View File

@ -501,9 +501,15 @@ cfgLoad(unsigned int argListSize, const char *argList[])
// Begin the command
cmdBegin();
// Acquire a lock if this command requires a lock
if (cfgLockRequired() && !cfgCommandHelp())
lockAcquireP(cfgOptionStr(cfgOptLockPath), cfgOptionStr(cfgOptStanza), cfgOptionStr(cfgOptExecId), cfgLockType());
// Init lock module if this command can lock
if (cfgLockType() != lockTypeNone && !cfgCommandHelp())
{
lockInit(cfgOptionStr(cfgOptLockPath), cfgOptionStr(cfgOptExecId), cfgOptionStr(cfgOptStanza), cfgLockType());
// Acquire a lock if this command requires a lock
if (cfgLockRequired())
lockAcquireP();
}
// Update options that have complex rules
cfgLoadUpdateOption();

View File

@ -401,6 +401,12 @@ unit:
name: storageHelper
shim:
storage/helper: ~
harness:
name: lock
shim:
common/lock:
function:
- lockInit
coverage:
- common/lock

View File

@ -29,7 +29,8 @@ hrnCmdBackup(void)
{
FUNCTION_HARNESS_VOID();
lockAcquireP(STR(testPath()), cfgOptionStr(cfgOptStanza), cfgOptionStr(cfgOptExecId), lockTypeBackup);
lockInit(STR(testPath()), cfgOptionStr(cfgOptExecId), cfgOptionStr(cfgOptStanza), lockTypeBackup);
lockAcquireP();
TRY_BEGIN()
{

View File

@ -17,6 +17,7 @@ Harness for Loading Test Configurations
#include "common/harnessConfig.h"
#include "common/harnessDebug.h"
#include "common/harnessLock.h"
#include "common/harnessLog.h"
#include "common/harnessStorageHelper.h"
#include "common/harnessTest.h"
@ -99,6 +100,11 @@ hrnCfgLoad(ConfigCommand commandId, const StringList *argListParam, const HrnCfg
if (cfgOptionValid(cfgOptExecId) && !cfgOptionTest(cfgOptExecId))
cfgOptionSet(cfgOptExecId, cfgSourceParam, VARSTRDEF("1-test"));
if (cfgOptionTest(cfgOptExecId) && cfgOptionTest(cfgOptLockPath) && cfgOptionTest(cfgOptStanza))
lockInit(cfgOptionStr(cfgOptLockPath), cfgOptionStr(cfgOptExecId), cfgOptionStr(cfgOptStanza), cfgLockType());
else
hrnLockUnInit();
FUNCTION_HARNESS_RETURN_VOID();
}

View File

@ -0,0 +1,45 @@
/***********************************************************************************************************************************
Lock Test Harness
***********************************************************************************************************************************/
#include "build.auto.h"
#include "common/harnessDebug.h"
#include "common/harnessLock.h"
/***********************************************************************************************************************************
Include shimmed C modules
***********************************************************************************************************************************/
{[SHIM_MODULE]}
/**********************************************************************************************************************************/
FN_EXTERN void
lockInit(const String *const path, const String *const execId, const String *const stanza, const LockType type)
{
FUNCTION_HARNESS_BEGIN();
FUNCTION_HARNESS_PARAM(STRING, path);
FUNCTION_HARNESS_PARAM(STRING, execId);
FUNCTION_HARNESS_PARAM(STRING, stanza);
FUNCTION_HARNESS_PARAM(ENUM, type);
FUNCTION_HARNESS_END();
hrnLockUnInit();
lockInit_SHIMMED(path, execId, stanza, type);
FUNCTION_HARNESS_RETURN_VOID();
}
/**********************************************************************************************************************************/
FN_EXTERN void
hrnLockUnInit(void)
{
FUNCTION_HARNESS_VOID();
// Free mem context it it exists
if (lockLocal.memContext != NULL)
{
memContextFree(lockLocal.memContext);
lockLocal = (struct LockLocal){0};
}
FUNCTION_HARNESS_RETURN_VOID();
}

View File

@ -0,0 +1,15 @@
/***********************************************************************************************************************************
Lock Test Harness
***********************************************************************************************************************************/
#ifndef TEST_COMMON_HARNESSLOCK_H
#define TEST_COMMON_HARNESSLOCK_H
#include "common/lock.h"
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
// Uninitialize lock module
FN_EXTERN void hrnLockUnInit(void);
#endif

View File

@ -725,11 +725,8 @@ testRun(void)
{
HRN_FORK_CHILD_BEGIN()
{
TEST_RESULT_VOID(
lockAcquireP(
cfgOptionStr(cfgOptLockPath), cfgOptionStr(cfgOptStanza), STRDEF("999-dededede"), cfgLockType(),
.timeout = 30000, .returnOnNoLock = true),
"acquire lock");
lockInit(cfgOptionStr(cfgOptLockPath), STRDEF("999-dededede"), cfgOptionStr(cfgOptStanza), cfgLockType());
TEST_RESULT_VOID(lockAcquireP(.timeout = 30000, .returnOnNoLock = true), "acquire lock");
// Notify parent that lock has been acquired
HRN_FORK_CHILD_NOTIFY_PUT();

View File

@ -749,9 +749,8 @@ testRun(void)
{
HRN_FORK_CHILD_BEGIN()
{
lockAcquireP(
cfgOptionStr(cfgOptLockPath), cfgOptionStr(cfgOptStanza), STRDEF("555-fefefefe"), cfgLockType(),
.timeout = 30000, .returnOnNoLock = true);
lockInit(cfgOptionStr(cfgOptLockPath), STRDEF("555-fefefefe"), cfgOptionStr(cfgOptStanza), cfgLockType());
lockAcquireP(.timeout = 30000, .returnOnNoLock = true);
// Notify parent that lock has been acquired
HRN_FORK_CHILD_NOTIFY_PUT();

View File

@ -2126,9 +2126,9 @@ testRun(void)
uint64_t sizeProgress = 0;
currentPercentComplete = 4567;
TEST_RESULT_VOID(
lockAcquireP(TEST_PATH_STR, cfgOptionStr(cfgOptStanza), cfgOptionStr(cfgOptExecId), lockTypeBackup),
"acquire backup lock");
lockInit(TEST_PATH_STR, cfgOptionStr(cfgOptExecId), cfgOptionStr(cfgOptStanza), lockTypeBackup);
TEST_RESULT_VOID(lockAcquireP(), "acquire backup lock");
TEST_RESULT_VOID(
backupJobResult(
manifest, STRDEF("host"), storageTest, strLstNew(), job, false, 0, &sizeProgress, &currentPercentComplete),

View File

@ -253,11 +253,8 @@ testRun(void)
{
HRN_FORK_CHILD_BEGIN()
{
TEST_RESULT_BOOL(
lockAcquireP(
STRDEF(HRN_PATH "/lock"), cfgOptionStr(cfgOptStanza), cfgOptionStr(cfgOptExecId), lockTypeArchive,
.timeout = 30000),
true, "child process acquires lock");
lockInit(STRDEF(HRN_PATH "/lock"), cfgOptionStr(cfgOptExecId), cfgOptionStr(cfgOptStanza), lockTypeArchive);
TEST_RESULT_BOOL(lockAcquireP(.timeout = 30000), true, "child process acquires lock");
// Notify parent that lock has been acquired
HRN_FORK_CHILD_NOTIFY_PUT();

View File

@ -107,8 +107,6 @@ testRun(void)
" ERR_STACK_TRACE\n"
" --------------------------------------------------------------------\n"
"P00 INFO: archive-push:async command end: aborted with exception [122]\n"
"P00 DEBUG: " TEST_PGB_PATH "/src/common/lock::lockRelease: (failOnNoLock: false)\n"
"P00 DEBUG: " TEST_PGB_PATH "/src/common/lock::lockRelease: => false\n"
"P00 DEBUG: " TEST_PGB_PATH "/src/command/exit::exitSafe: => 122");
}
TRY_END();

View File

@ -236,9 +236,8 @@ testRun(void)
{
HRN_FORK_CHILD_BEGIN()
{
TEST_RESULT_INT_NE(
lockAcquireP(cfgOptionStr(cfgOptLockPath), STRDEF("stanza1"), STRDEF("999-ffffffff"), lockTypeBackup), -1,
"create backup/expire lock");
lockInit(cfgOptionStr(cfgOptLockPath), STRDEF("999-ffffffff"), STRDEF("stanza1"), lockTypeBackup);
TEST_RESULT_INT_NE(lockAcquireP(), -1, "create backup/expire lock");
// Notify parent that lock has been acquired
HRN_FORK_CHILD_NOTIFY_PUT();
@ -429,9 +428,8 @@ testRun(void)
{
HRN_FORK_CHILD_BEGIN()
{
TEST_RESULT_INT_NE(
lockAcquireP(cfgOptionStr(cfgOptLockPath), STRDEF("stanza1"), STRDEF("777-afafafaf"), lockTypeBackup), -1,
"create backup/expire lock");
lockInit(cfgOptionStr(cfgOptLockPath), STRDEF("777-afafafaf"), STRDEF("stanza1"), lockTypeBackup);
TEST_RESULT_INT_NE(lockAcquireP(), -1, "create backup/expire lock");
TEST_RESULT_VOID(lockWriteDataP(lockTypeBackup), "write lock data");
// Notify parent that lock has been acquired
@ -1025,9 +1023,8 @@ testRun(void)
{
HRN_FORK_CHILD_BEGIN()
{
TEST_RESULT_INT_NE(
lockAcquireP(cfgOptionStr(cfgOptLockPath), STRDEF("stanza2"), STRDEF("999-ffffffff"), lockTypeBackup), -1,
"create backup/expire lock");
lockInit(cfgOptionStr(cfgOptLockPath), STRDEF("999-ffffffff"), STRDEF("stanza2"), lockTypeBackup);
TEST_RESULT_INT_NE(lockAcquireP(), -1, "create backup/expire lock");
TEST_RESULT_VOID(lockWriteDataP(lockTypeBackup, .percentComplete = VARUINT(4545)), "write lock data");
// Notify parent that lock has been acquired
@ -1465,9 +1462,8 @@ testRun(void)
{
HRN_FORK_CHILD_BEGIN()
{
TEST_RESULT_INT_NE(
lockAcquireP(cfgOptionStr(cfgOptLockPath), STRDEF("stanza2"), STRDEF("999-ffffffff"), lockTypeBackup), -1,
"create backup/expire lock");
lockInit(cfgOptionStr(cfgOptLockPath), STRDEF("999-ffffffff"), STRDEF("stanza2"), lockTypeBackup);
TEST_RESULT_INT_NE(lockAcquireP(), -1, "create backup/expire lock");
TEST_RESULT_VOID(lockWriteDataP(lockTypeBackup, .percentComplete = VARUINT(5555)), "write lock data");
// Notify parent that lock has been acquired

View File

@ -158,53 +158,55 @@ testRun(void)
TEST_RESULT_BOOL(lockRelease(false), false, "release when there is no lock");
// -------------------------------------------------------------------------------------------------------------------------
lockLocal.execId = STRDEF("1-test");
lockInit(TEST_PATH_STR, STRDEF("1-test"), stanza, lockTypeArchive);
TEST_ASSIGN(lockFdTest, lockAcquireFile(archiveLockFile, 0, true), "archive lock by file");
TEST_RESULT_BOOL(
lockAcquireP(TEST_PATH_STR, stanza, STRDEF("2-test"), lockTypeArchive, .returnOnNoLock = true), false,
"archive already locked");
TEST_RESULT_BOOL(lockAcquireP(.returnOnNoLock = true), false, "archive already locked");
TEST_ERROR_FMT(
lockAcquireP(TEST_PATH_STR, stanza, STRDEF("2-test"), lockTypeArchive), LockAcquireError,
lockAcquireP(), LockAcquireError,
"unable to acquire lock on file '%s': Resource temporarily unavailable\n"
"HINT: is another pgBackRest process running?",
strZ(archiveLockFile));
lockLocal.type = lockTypeAll;
TEST_ERROR_FMT(
lockAcquireP(TEST_PATH_STR, stanza, STRDEF("2-test"), lockTypeAll), LockAcquireError,
lockAcquireP(), LockAcquireError,
"unable to acquire lock on file '%s': Resource temporarily unavailable\n"
"HINT: is another pgBackRest process running?", strZ(archiveLockFile));
TEST_RESULT_VOID(lockReleaseFile(lockFdTest, archiveLockFile), "release lock");
// -------------------------------------------------------------------------------------------------------------------------
lockLocal.execId = STRDEF("1-test");
lockInit(TEST_PATH_STR, STRDEF("1-test"), stanza, lockTypeArchive);
TEST_RESULT_BOOL(lockAcquireP(TEST_PATH_STR, stanza, STRDEF("1-test"), lockTypeArchive), true, "archive lock");
TEST_RESULT_BOOL(lockAcquireP(), true, "archive lock");
TEST_RESULT_BOOL(storageExistsP(storageTest, archiveLockFile), true, "archive lock file was created");
TEST_ERROR(
lockAcquireP(TEST_PATH_STR, stanza, STRDEF("1-test"), lockTypeArchive, .returnOnNoLock = true), AssertError,
"lock is already held by this process");
TEST_ERROR(lockAcquireP(.returnOnNoLock = true), AssertError, "lock is already held by this process");
TEST_RESULT_VOID(lockRelease(true), "release archive lock");
// -------------------------------------------------------------------------------------------------------------------------
lockLocal.execId = STRDEF("2-test");
lockInit(TEST_PATH_STR, STRDEF("1-test"), stanza, lockTypeBackup);
TEST_ASSIGN(lockFdTest, lockAcquireFile(backupLockFile, 0, true), "backup lock by file");
TEST_ERROR_FMT(
lockAcquireP(TEST_PATH_STR, stanza, STRDEF("2-test"), lockTypeBackup), LockAcquireError,
lockAcquireP(), LockAcquireError,
"unable to acquire lock on file '%s': Resource temporarily unavailable\n"
"HINT: is another pgBackRest process running?", strZ(backupLockFile));
lockLocal.type = lockTypeAll;
TEST_ERROR_FMT(
lockAcquireP(TEST_PATH_STR, stanza, STRDEF("2-test"), lockTypeAll), LockAcquireError,
lockAcquireP(), LockAcquireError,
"unable to acquire lock on file '%s': Resource temporarily unavailable\n"
"HINT: is another pgBackRest process running?", strZ(backupLockFile));
TEST_RESULT_VOID(lockReleaseFile(lockFdTest, archiveLockFile), "release archive lock");
TEST_RESULT_VOID(lockReleaseFile(lockFdTest, backupLockFile), "release backup lock");
// -------------------------------------------------------------------------------------------------------------------------
lockLocal.execId = STRDEF("1-test");
lockInit(TEST_PATH_STR, STRDEF("1-test"), stanza, lockTypeAll);
TEST_RESULT_BOOL(lockAcquireP(TEST_PATH_STR, stanza, STRDEF("1-test"), lockTypeAll), true, "all lock");
TEST_RESULT_BOOL(lockAcquireP(), true, "all lock");
TEST_RESULT_BOOL(storageExistsP(storageTest, archiveLockFile), true, "archive lock file was created");
TEST_RESULT_BOOL(storageExistsP(storageTest, backupLockFile), true, "backup lock file was created");
@ -239,8 +241,8 @@ testRun(void)
"verify percentComplete");
TEST_ERROR(
lockAcquireP(TEST_PATH_STR, stanza, STRDEF("1-test"), lockTypeAll, .returnOnNoLock = true), AssertError,
"assertion '!param.returnOnNoLock || lockType != lockTypeAll' failed");
lockAcquireP(.returnOnNoLock = true), AssertError,
"assertion '!param.returnOnNoLock || lockLocal.type != lockTypeAll' failed");
TEST_RESULT_VOID(lockRelease(true), "release all locks");
TEST_RESULT_BOOL(storageExistsP(storageTest, archiveLockFile), false, "archive lock file was removed");
@ -249,15 +251,16 @@ testRun(void)
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("acquire lock on the same exec-id and release");
TEST_RESULT_BOOL(lockAcquireP(TEST_PATH_STR, stanza, STRDEF("1-test"), lockTypeBackup), true, "backup lock");
lockInit(TEST_PATH_STR, STRDEF("1-test"), stanza, lockTypeBackup);
TEST_RESULT_BOOL(lockAcquireP(), true, "backup lock");
// Make it look there is no lock
lockFdTest = lockLocal.file[lockTypeBackup].fd;
String *lockFileTest = strDup(lockLocal.file[lockTypeBackup].name);
lockLocal.held = lockTypeNone;
lockLocal.held = false;
TEST_RESULT_BOOL(
lockAcquireP(TEST_PATH_STR, stanza, STRDEF("1-test"), lockTypeBackup), true, "backup lock again");
TEST_RESULT_BOOL(lockAcquireP(), true, "backup lock again");
TEST_RESULT_VOID(lockRelease(true), "release backup lock");
// Release lock manually
@ -281,10 +284,9 @@ testRun(void)
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("execId && pid valid file");
const String *stanza = STRDEF("1-test");
lockLocal.execId = STRDEF("1-test");
lockInit(TEST_PATH_STR, STRDEF("1-test"), STRDEF("1-test"), lockTypeBackup);
TEST_RESULT_BOOL(lockAcquireP(TEST_PATH_STR, stanza, STRDEF("1-test"), lockTypeBackup), true, "backup lock");
TEST_RESULT_BOOL(lockAcquireP(), true, "backup lock");
TEST_RESULT_BOOL(storageExistsP(storageTest, lockLocal.file[lockTypeBackup].name), true, "backup lock file was created");
// Overwrite backup lock file with execId of 1-test and pid of 12345
@ -317,7 +319,9 @@ testRun(void)
{
HRN_FORK_CHILD_BEGIN()
{
TEST_RESULT_BOOL(lockAcquireP(TEST_PATH_STR, STRDEF("test"), STRDEF("test"), lockTypeBackup), true, "acquire lock");
lockInit(TEST_PATH_STR, STRDEF("1-test"), STRDEF("test"), lockTypeBackup);
TEST_RESULT_BOOL(lockAcquireP(), true, "acquire lock");
// Overwrite lock file with bogus data
THROW_ON_SYS_ERROR_FMT(
@ -361,7 +365,9 @@ testRun(void)
{
HRN_FORK_CHILD_BEGIN()
{
TEST_RESULT_BOOL(lockAcquireP(TEST_PATH_STR, STRDEF("test"), STRDEF("test"), lockTypeBackup), true, "acquire lock");
lockInit(TEST_PATH_STR, STRDEF("1-test"), STRDEF("test"), lockTypeBackup);
TEST_RESULT_BOOL(lockAcquireP(), true, "acquire lock");
// Notify parent that lock has been acquired
HRN_FORK_CHILD_NOTIFY_PUT();
@ -380,7 +386,7 @@ testRun(void)
TEST_ASSIGN(result, lockRead(TEST_PATH_STR, STRDEF("test"), lockTypeBackup), "lock read");
TEST_RESULT_BOOL(result.data.processId != 0, true, "check processId");
TEST_RESULT_STR_Z(result.data.execId, "test", "check execId");
TEST_RESULT_STR_Z(result.data.execId, "1-test", "check execId");
TEST_STORAGE_LIST(storageTest, NULL, "test-backup.lock\n");