1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2024-12-14 10:13:05 +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() HRN_FORK_CHILD_BEGIN()
{ {
TEST_RESULT_INT_NE( TEST_RESULT_INT_NE(lockAcquireP(), -1, "create backup/expire lock");
lockAcquireP(cfgOptionStr(cfgOptLockPath), STRDEF("stanza1"), STRDEF("999-ffffffff"), lockTypeBackup), -1,
"create backup/expire lock");
// Notify parent that lock has been acquired // Notify parent that lock has been acquired
HRN_FORK_CHILD_NOTIFY_PUT(); HRN_FORK_CHILD_NOTIFY_PUT();

View File

@ -530,9 +530,7 @@ HRN_FORK_BEGIN()
{ {
HRN_FORK_CHILD_BEGIN() HRN_FORK_CHILD_BEGIN()
{ {
TEST_RESULT_INT_NE( TEST_RESULT_INT_NE(lockAcquireP(), -1, "create backup/expire lock");
lockAcquireP(cfgOptionStr(cfgOptLockPath), STRDEF("stanza1"), STRDEF("999-ffffffff"), lockTypeBackup), -1,
"create backup/expire lock");
// Notify parent that lock has been acquired // Notify parent that lock has been acquired
HRN_FORK_CHILD_NOTIFY_PUT(); 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 // 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 // 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. // the async process was launched by another process.
if (!forked && (!found || !queueFull) && if (!forked && (!found || !queueFull) && lockAcquireP(.returnOnNoLock = true))
lockAcquireP(
cfgOptionStr(cfgOptLockPath), cfgOptionStr(cfgOptStanza), cfgOptionStr(cfgOptExecId), cfgLockType(),
.returnOnNoLock = true))
{ {
// Get control info // Get control info
PgControl pgControl = pgControlFromFile(storagePg(), cfgOptionStrNull(cfgOptPgVersionForce)); 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 // 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 // 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. // one async process being launched.
if (!pushed && !forked && if (!pushed && !forked && lockAcquireP(.returnOnNoLock = true))
lockAcquireP(
cfgOptionStr(cfgOptLockPath), cfgOptionStr(cfgOptStanza), cfgOptionStr(cfgOptExecId), cfgLockType(),
.returnOnNoLock = true))
{ {
// The async process should not output on the console at all // The async process should not output on the console at all
KeyValue *optionReplace = kvNew(); KeyValue *optionReplace = kvNew();

View File

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

View File

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

View File

@ -37,6 +37,9 @@ Constants
/*********************************************************************************************************************************** /***********************************************************************************************************************************
Functions 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 // 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. // single lock (archive or backup), but the stanza commands all need to lock both.
typedef struct LockAcquireParam typedef struct LockAcquireParam
@ -46,11 +49,10 @@ typedef struct LockAcquireParam
bool returnOnNoLock; // Return when no lock acquired (rather than throw an error) bool returnOnNoLock; // Return when no lock acquired (rather than throw an error)
} LockAcquireParam; } LockAcquireParam;
#define lockAcquireP(lockPath, stanza, execId, lockType, ...) \ #define lockAcquireP(...) \
lockAcquire(lockPath, stanza, execId, lockType, (LockAcquireParam) {VAR_PARAM_INIT, __VA_ARGS__}) lockAcquire((LockAcquireParam) {VAR_PARAM_INIT, __VA_ARGS__})
FN_EXTERN bool lockAcquire( FN_EXTERN bool lockAcquire(LockAcquireParam param);
const String *lockPath, const String *stanza, const String *execId, LockType lockType, LockAcquireParam param);
// Release a lock // Release a lock
FN_EXTERN bool lockRelease(bool failOnNoLock); FN_EXTERN bool lockRelease(bool failOnNoLock);

View File

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

View File

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

View File

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

View File

@ -17,6 +17,7 @@ Harness for Loading Test Configurations
#include "common/harnessConfig.h" #include "common/harnessConfig.h"
#include "common/harnessDebug.h" #include "common/harnessDebug.h"
#include "common/harnessLock.h"
#include "common/harnessLog.h" #include "common/harnessLog.h"
#include "common/harnessStorageHelper.h" #include "common/harnessStorageHelper.h"
#include "common/harnessTest.h" #include "common/harnessTest.h"
@ -99,6 +100,11 @@ hrnCfgLoad(ConfigCommand commandId, const StringList *argListParam, const HrnCfg
if (cfgOptionValid(cfgOptExecId) && !cfgOptionTest(cfgOptExecId)) if (cfgOptionValid(cfgOptExecId) && !cfgOptionTest(cfgOptExecId))
cfgOptionSet(cfgOptExecId, cfgSourceParam, VARSTRDEF("1-test")); 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(); 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() HRN_FORK_CHILD_BEGIN()
{ {
TEST_RESULT_VOID( lockInit(cfgOptionStr(cfgOptLockPath), STRDEF("999-dededede"), cfgOptionStr(cfgOptStanza), cfgLockType());
lockAcquireP( TEST_RESULT_VOID(lockAcquireP(.timeout = 30000, .returnOnNoLock = true), "acquire lock");
cfgOptionStr(cfgOptLockPath), cfgOptionStr(cfgOptStanza), STRDEF("999-dededede"), cfgLockType(),
.timeout = 30000, .returnOnNoLock = true),
"acquire lock");
// Notify parent that lock has been acquired // Notify parent that lock has been acquired
HRN_FORK_CHILD_NOTIFY_PUT(); HRN_FORK_CHILD_NOTIFY_PUT();

View File

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

View File

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

View File

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

View File

@ -107,8 +107,6 @@ testRun(void)
" ERR_STACK_TRACE\n" " ERR_STACK_TRACE\n"
" --------------------------------------------------------------------\n" " --------------------------------------------------------------------\n"
"P00 INFO: archive-push:async command end: aborted with exception [122]\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"); "P00 DEBUG: " TEST_PGB_PATH "/src/command/exit::exitSafe: => 122");
} }
TRY_END(); TRY_END();

View File

@ -236,9 +236,8 @@ testRun(void)
{ {
HRN_FORK_CHILD_BEGIN() HRN_FORK_CHILD_BEGIN()
{ {
TEST_RESULT_INT_NE( lockInit(cfgOptionStr(cfgOptLockPath), STRDEF("999-ffffffff"), STRDEF("stanza1"), lockTypeBackup);
lockAcquireP(cfgOptionStr(cfgOptLockPath), STRDEF("stanza1"), STRDEF("999-ffffffff"), lockTypeBackup), -1, TEST_RESULT_INT_NE(lockAcquireP(), -1, "create backup/expire lock");
"create backup/expire lock");
// Notify parent that lock has been acquired // Notify parent that lock has been acquired
HRN_FORK_CHILD_NOTIFY_PUT(); HRN_FORK_CHILD_NOTIFY_PUT();
@ -429,9 +428,8 @@ testRun(void)
{ {
HRN_FORK_CHILD_BEGIN() HRN_FORK_CHILD_BEGIN()
{ {
TEST_RESULT_INT_NE( lockInit(cfgOptionStr(cfgOptLockPath), STRDEF("777-afafafaf"), STRDEF("stanza1"), lockTypeBackup);
lockAcquireP(cfgOptionStr(cfgOptLockPath), STRDEF("stanza1"), STRDEF("777-afafafaf"), lockTypeBackup), -1, TEST_RESULT_INT_NE(lockAcquireP(), -1, "create backup/expire lock");
"create backup/expire lock");
TEST_RESULT_VOID(lockWriteDataP(lockTypeBackup), "write lock data"); TEST_RESULT_VOID(lockWriteDataP(lockTypeBackup), "write lock data");
// Notify parent that lock has been acquired // Notify parent that lock has been acquired
@ -1025,9 +1023,8 @@ testRun(void)
{ {
HRN_FORK_CHILD_BEGIN() HRN_FORK_CHILD_BEGIN()
{ {
TEST_RESULT_INT_NE( lockInit(cfgOptionStr(cfgOptLockPath), STRDEF("999-ffffffff"), STRDEF("stanza2"), lockTypeBackup);
lockAcquireP(cfgOptionStr(cfgOptLockPath), STRDEF("stanza2"), STRDEF("999-ffffffff"), lockTypeBackup), -1, TEST_RESULT_INT_NE(lockAcquireP(), -1, "create backup/expire lock");
"create backup/expire lock");
TEST_RESULT_VOID(lockWriteDataP(lockTypeBackup, .percentComplete = VARUINT(4545)), "write lock data"); TEST_RESULT_VOID(lockWriteDataP(lockTypeBackup, .percentComplete = VARUINT(4545)), "write lock data");
// Notify parent that lock has been acquired // Notify parent that lock has been acquired
@ -1465,9 +1462,8 @@ testRun(void)
{ {
HRN_FORK_CHILD_BEGIN() HRN_FORK_CHILD_BEGIN()
{ {
TEST_RESULT_INT_NE( lockInit(cfgOptionStr(cfgOptLockPath), STRDEF("999-ffffffff"), STRDEF("stanza2"), lockTypeBackup);
lockAcquireP(cfgOptionStr(cfgOptLockPath), STRDEF("stanza2"), STRDEF("999-ffffffff"), lockTypeBackup), -1, TEST_RESULT_INT_NE(lockAcquireP(), -1, "create backup/expire lock");
"create backup/expire lock");
TEST_RESULT_VOID(lockWriteDataP(lockTypeBackup, .percentComplete = VARUINT(5555)), "write lock data"); TEST_RESULT_VOID(lockWriteDataP(lockTypeBackup, .percentComplete = VARUINT(5555)), "write lock data");
// Notify parent that lock has been acquired // 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"); 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_ASSIGN(lockFdTest, lockAcquireFile(archiveLockFile, 0, true), "archive lock by file");
TEST_RESULT_BOOL( TEST_RESULT_BOOL(lockAcquireP(.returnOnNoLock = true), false, "archive already locked");
lockAcquireP(TEST_PATH_STR, stanza, STRDEF("2-test"), lockTypeArchive, .returnOnNoLock = true), false,
"archive already locked");
TEST_ERROR_FMT( 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" "unable to acquire lock on file '%s': Resource temporarily unavailable\n"
"HINT: is another pgBackRest process running?", "HINT: is another pgBackRest process running?",
strZ(archiveLockFile)); strZ(archiveLockFile));
lockLocal.type = lockTypeAll;
TEST_ERROR_FMT( 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" "unable to acquire lock on file '%s': Resource temporarily unavailable\n"
"HINT: is another pgBackRest process running?", strZ(archiveLockFile)); "HINT: is another pgBackRest process running?", strZ(archiveLockFile));
TEST_RESULT_VOID(lockReleaseFile(lockFdTest, archiveLockFile), "release lock"); 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_RESULT_BOOL(storageExistsP(storageTest, archiveLockFile), true, "archive lock file was created");
TEST_ERROR( TEST_ERROR(lockAcquireP(.returnOnNoLock = true), AssertError, "lock is already held by this process");
lockAcquireP(TEST_PATH_STR, stanza, STRDEF("1-test"), lockTypeArchive, .returnOnNoLock = true), AssertError,
"lock is already held by this process");
TEST_RESULT_VOID(lockRelease(true), "release archive lock"); 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_ASSIGN(lockFdTest, lockAcquireFile(backupLockFile, 0, true), "backup lock by file");
TEST_ERROR_FMT( 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" "unable to acquire lock on file '%s': Resource temporarily unavailable\n"
"HINT: is another pgBackRest process running?", strZ(backupLockFile)); "HINT: is another pgBackRest process running?", strZ(backupLockFile));
lockLocal.type = lockTypeAll;
TEST_ERROR_FMT( 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" "unable to acquire lock on file '%s': Resource temporarily unavailable\n"
"HINT: is another pgBackRest process running?", strZ(backupLockFile)); "HINT: is another pgBackRest process running?", strZ(backupLockFile));
TEST_RESULT_VOID(lockReleaseFile(lockFdTest, archiveLockFile), "release archive lock"); TEST_RESULT_VOID(lockReleaseFile(lockFdTest, archiveLockFile), "release archive lock");
TEST_RESULT_VOID(lockReleaseFile(lockFdTest, backupLockFile), "release backup 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, archiveLockFile), true, "archive lock file was created");
TEST_RESULT_BOOL(storageExistsP(storageTest, backupLockFile), true, "backup lock file was created"); TEST_RESULT_BOOL(storageExistsP(storageTest, backupLockFile), true, "backup lock file was created");
@ -239,8 +241,8 @@ testRun(void)
"verify percentComplete"); "verify percentComplete");
TEST_ERROR( TEST_ERROR(
lockAcquireP(TEST_PATH_STR, stanza, STRDEF("1-test"), lockTypeAll, .returnOnNoLock = true), AssertError, lockAcquireP(.returnOnNoLock = true), AssertError,
"assertion '!param.returnOnNoLock || lockType != lockTypeAll' failed"); "assertion '!param.returnOnNoLock || lockLocal.type != lockTypeAll' failed");
TEST_RESULT_VOID(lockRelease(true), "release all locks"); TEST_RESULT_VOID(lockRelease(true), "release all locks");
TEST_RESULT_BOOL(storageExistsP(storageTest, archiveLockFile), false, "archive lock file was removed"); 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_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 // Make it look there is no lock
lockFdTest = lockLocal.file[lockTypeBackup].fd; lockFdTest = lockLocal.file[lockTypeBackup].fd;
String *lockFileTest = strDup(lockLocal.file[lockTypeBackup].name); String *lockFileTest = strDup(lockLocal.file[lockTypeBackup].name);
lockLocal.held = lockTypeNone; lockLocal.held = false;
TEST_RESULT_BOOL( TEST_RESULT_BOOL(lockAcquireP(), true, "backup lock again");
lockAcquireP(TEST_PATH_STR, stanza, STRDEF("1-test"), lockTypeBackup), true, "backup lock again");
TEST_RESULT_VOID(lockRelease(true), "release backup lock"); TEST_RESULT_VOID(lockRelease(true), "release backup lock");
// Release lock manually // Release lock manually
@ -281,10 +284,9 @@ testRun(void)
// ------------------------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("execId && pid valid file"); TEST_TITLE("execId && pid valid file");
const String *stanza = STRDEF("1-test"); lockInit(TEST_PATH_STR, STRDEF("1-test"), STRDEF("1-test"), lockTypeBackup);
lockLocal.execId = STRDEF("1-test");
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"); 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 // Overwrite backup lock file with execId of 1-test and pid of 12345
@ -317,7 +319,9 @@ testRun(void)
{ {
HRN_FORK_CHILD_BEGIN() 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 // Overwrite lock file with bogus data
THROW_ON_SYS_ERROR_FMT( THROW_ON_SYS_ERROR_FMT(
@ -361,7 +365,9 @@ testRun(void)
{ {
HRN_FORK_CHILD_BEGIN() 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 // Notify parent that lock has been acquired
HRN_FORK_CHILD_NOTIFY_PUT(); HRN_FORK_CHILD_NOTIFY_PUT();
@ -380,7 +386,7 @@ testRun(void)
TEST_ASSIGN(result, lockRead(TEST_PATH_STR, STRDEF("test"), lockTypeBackup), "lock read"); TEST_ASSIGN(result, lockRead(TEST_PATH_STR, STRDEF("test"), lockTypeBackup), "lock read");
TEST_RESULT_BOOL(result.data.processId != 0, true, "check processId"); 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"); TEST_STORAGE_LIST(storageTest, NULL, "test-backup.lock\n");