1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-03-05 15:05:48 +02:00

Add Wait object and time module.

This commit is contained in:
David Steele 2018-01-16 13:05:00 -05:00
parent 721d1127a0
commit d633417e5d
9 changed files with 293 additions and 1 deletions

View File

@ -54,7 +54,11 @@
</release-item>
<release-item>
<p>Add <code>Buffer</code>, <code>Ini</code>, <code>KeyValue</code>, <code>List</code>, <code>RegExp</code>, <code>Storage</code>, <code>String</code>, <code>StringList</code>, <code>Variant</code>, and <code>VariantList</code> objects.</p>
<p>Add <code>Buffer</code>, <code>Ini</code>, <code>KeyValue</code>, <code>List</code>, <code>RegExp</code>, <code>Storage</code>, <code>String</code>, <code>StringList</code>, <code>Variant</code>, <code>VariantList</code>, and <code>Wait</code> objects.</p>
</release-item>
<release-item>
<p>Add <code>time</code> module.</p>
</release-item>
<release-item>

View File

@ -8,6 +8,7 @@ pgbackrest: \
common/ini.o \
common/memContext.o \
common/regExp.o \
common/time.o \
common/type/buffer.o \
common/type/keyValue.o \
common/type/list.o \
@ -15,6 +16,7 @@ pgbackrest: \
common/type/stringList.o \
common/type/variant.o \
common/type/variantList.o \
common/wait.o \
config/config.o \
config/define.o \
config/parse.o \
@ -27,6 +29,7 @@ pgbackrest: \
common/ini.o \
common/memContext.o \
common/regExp.o \
common/time.o \
common/type/buffer.o \
common/type/keyValue.o \
common/type/list.o \
@ -34,6 +37,7 @@ pgbackrest: \
common/type/stringList.o \
common/type/variant.o \
common/type/variantList.o \
common/wait.o \
config/config.o \
config/define.o \
config/parse.o \

30
src/common/time.c Normal file
View File

@ -0,0 +1,30 @@
/***********************************************************************************************************************************
Time Management
***********************************************************************************************************************************/
#include <sys/time.h>
#include "common/time.h"
#include "common/type.h"
/***********************************************************************************************************************************
Epoch time in microseconds
***********************************************************************************************************************************/
TimeUSec
timeUSec()
{
struct timeval currentTime;
gettimeofday(&currentTime, NULL);
return ((TimeUSec)currentTime.tv_sec * USEC_PER_SEC) + (TimeUSec)currentTime.tv_usec;
}
/***********************************************************************************************************************************
Sleep for specified microseconds
***********************************************************************************************************************************/
void
sleepUSec(TimeUSec sleepUSec)
{
struct timeval delay;
delay.tv_sec = sleepUSec / USEC_PER_SEC;
delay.tv_usec = sleepUSec % USEC_PER_SEC;
select(0, NULL, NULL, NULL, &delay);
}

25
src/common/time.h Normal file
View File

@ -0,0 +1,25 @@
/***********************************************************************************************************************************
Time Management
***********************************************************************************************************************************/
#ifndef COMMON_TIME_H
#define COMMON_TIME_H
#include "common/type.h"
/***********************************************************************************************************************************
Time types
***********************************************************************************************************************************/
typedef uint64 TimeUSec;
/***********************************************************************************************************************************
Constants describing number if sub-units in a second
***********************************************************************************************************************************/
#define USEC_PER_SEC ((TimeUSec)1000000)
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
void sleepUSec(TimeUSec);
TimeUSec timeUSec();
#endif

106
src/common/wait.c Normal file
View File

@ -0,0 +1,106 @@
/***********************************************************************************************************************************
Wait Handler
***********************************************************************************************************************************/
#include "common/memContext.h"
#include "common/time.h"
#include "common/wait.h"
/***********************************************************************************************************************************
Contains information about the wait handler
***********************************************************************************************************************************/
struct Wait
{
MemContext *memContext; // Context that contains the wait handler
TimeUSec waitTime; // Total time to wait (in usec)
TimeUSec sleepTime; // Next sleep time (in usec)
TimeUSec sleepPrevTime; // Previous time slept (in usec)
TimeUSec beginTime; // Time the wait began (in epoch usec)
};
/***********************************************************************************************************************************
New wait handler
***********************************************************************************************************************************/
Wait *
waitNew(double waitTime)
{
// Make sure wait time is valid
if (waitTime < 0.1 || waitTime > 999999.0)
THROW(AssertError, "waitTime must be >= 0.1 and <= 999999.0");
// Allocate wait object
Wait *this = NULL;
MEM_CONTEXT_NEW_BEGIN("wait")
{
// Create object
this = memNew(sizeof(Wait));
this->memContext = MEM_CONTEXT_NEW();
// Store time
this->waitTime = (TimeUSec)(waitTime * USEC_PER_SEC);
// Calculate first sleep time -- start with 1/10th of a second for anything >= 1 second
if (this->waitTime >= USEC_PER_SEC)
this->sleepTime = USEC_PER_SEC / 10;
// Unless the wait time is really small -- in that case divide wait time by 10
else
this->sleepTime = this->waitTime / 10;
// Get beginning time
this->beginTime = timeUSec();
}
MEM_CONTEXT_NEW_END();
return this;
}
/***********************************************************************************************************************************
Wait and return whether the caller has more time left
***********************************************************************************************************************************/
bool
waitMore(Wait *this)
{
bool result = false;
// If sleep is 0 then the wait time has already ended
if (this->sleepTime > 0)
{
// Sleep required amount
sleepUSec(this->sleepTime);
// Get the end time
TimeUSec elapsedTime = timeUSec() - this->beginTime;
// Is there more time to go?
if (elapsedTime < this->waitTime)
{
// Calculate sleep time as a sum of current and last (a Fibonacci-type sequence)
TimeUSec sleepNextTime = this->sleepTime + this->sleepPrevTime;
// Make sure sleep time does not go beyond end time (this won't be negative because of the if condition above)
if (sleepNextTime > this->waitTime - elapsedTime)
sleepNextTime = this->waitTime - elapsedTime;
// Store new sleep times
this->sleepPrevTime = this->sleepTime;
this->sleepTime = sleepNextTime;
}
// Else set sleep to zero so next call will return false
else
this->sleepTime = 0;
// Need to wait more
result = true;
}
return result;
}
/***********************************************************************************************************************************
Free the wait
***********************************************************************************************************************************/
void
waitFree(Wait *this)
{
memContextFree(this->memContext);
}

19
src/common/wait.h Normal file
View File

@ -0,0 +1,19 @@
/***********************************************************************************************************************************
Wait Handler
***********************************************************************************************************************************/
#ifndef COMMON_WAIT_H
#define COMMON_WAIT_H
/***********************************************************************************************************************************
Ini object
***********************************************************************************************************************************/
typedef struct Wait Wait;
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
Wait *waitNew(double waitTime);
bool waitMore(Wait *this);
void waitFree(Wait *this);
#endif

View File

@ -131,6 +131,26 @@ my $oTestDef =
'common/memContext' => TESTDEF_COVERAGE_FULL,
},
},
{
&TESTDEF_NAME => 'time',
&TESTDEF_TOTAL => 2,
&TESTDEF_C => true,
&TESTDEF_COVERAGE =>
{
'common/time' => TESTDEF_COVERAGE_FULL,
},
},
{
&TESTDEF_NAME => 'wait',
&TESTDEF_TOTAL => 1,
&TESTDEF_C => true,
&TESTDEF_COVERAGE =>
{
'common/wait' => TESTDEF_COVERAGE_FULL,
},
},
{
&TESTDEF_NAME => 'type-list',
&TESTDEF_TOTAL => 2,

View File

@ -0,0 +1,30 @@
/***********************************************************************************************************************************
Test Time Management
***********************************************************************************************************************************/
/***********************************************************************************************************************************
Test Run
***********************************************************************************************************************************/
void testRun()
{
// *****************************************************************************************************************************
if (testBegin("timeUSec()"))
{
// Make sure the time returned is between 2017 and 2100
TEST_RESULT_BOOL(timeUSec() > (TimeUSec)1483228800000000, true, "lower range check");
TEST_RESULT_BOOL(timeUSec() < (TimeUSec)4102444800000000, true, "upper range check");
}
// *****************************************************************************************************************************
if (testBegin("sleepUSec()"))
{
// Sleep and measure time slept
TimeUSec begin = timeUSec();
sleepUSec(1400000);
TimeUSec end = timeUSec();
// Check bounds for time slept (within a range of .1 seconds)
TEST_RESULT_BOOL(end - begin > (TimeUSec)1400000, true, "lower range check");
TEST_RESULT_BOOL(end - begin < (TimeUSec)1500000, true, "upper range check");
}
}

View File

@ -0,0 +1,54 @@
/***********************************************************************************************************************************
Test Wait Handler
***********************************************************************************************************************************/
/***********************************************************************************************************************************
Test Run
***********************************************************************************************************************************/
void testRun()
{
// *****************************************************************************************************************************
if (testBegin("waitNew(), waitMore, and waitFree()"))
{
Wait *wait = NULL;
TEST_ERROR(waitNew(0.01), AssertError, "waitTime must be >= 0.1 and <= 999999.0");
TEST_ERROR(waitNew(9999999), AssertError, "waitTime must be >= 0.1 and <= 999999.0");
// -------------------------------------------------------------------------------------------------------------------------
unsigned long begin = timeUSec();
TEST_ASSIGN(wait, waitNew(0.2), "new wait = 0.2 sec");
TEST_RESULT_DOUBLE(wait->waitTime, 200000, " check wait time");
TEST_RESULT_DOUBLE(wait->sleepTime, 20000, " check sleep time");
TEST_RESULT_DOUBLE(wait->sleepPrevTime, 0, " check sleep prev time");
TEST_RESULT_BOOL(wait->beginTime > (unsigned long)1483228800000000, true, " check begin time");
while (waitMore(wait));
unsigned long end = timeUSec();
// Check bounds for time slept (within a range of .1 seconds)
TEST_RESULT_BOOL(end - begin >= wait->waitTime, true, " lower range check");
TEST_RESULT_BOOL(end - begin < wait->waitTime + 100000, true, " upper range check");
TEST_RESULT_VOID(waitFree(wait), " free wait");
// -------------------------------------------------------------------------------------------------------------------------
begin = timeUSec();
TEST_ASSIGN(wait, waitNew(1.1), "new wait = 1.1 sec");
TEST_RESULT_DOUBLE(wait->waitTime, 1100000, " check wait time");
TEST_RESULT_DOUBLE(wait->sleepTime, 100000, " check sleep time");
TEST_RESULT_DOUBLE(wait->sleepPrevTime, 0, " check sleep prev time");
TEST_RESULT_BOOL(wait->beginTime > (unsigned long)1483228800000000, true, " check begin time");
while (waitMore(wait));
end = timeUSec();
// Check bounds for time slept (within a range of .1 seconds)
TEST_RESULT_BOOL(end - begin >= wait->waitTime, true, " lower range check");
TEST_RESULT_BOOL(end - begin < wait->waitTime + 1200000, true, " upper range check");
TEST_RESULT_VOID(waitFree(wait), " free wait");
}
}