Last active
August 19, 2022 13:10
-
-
Save mrbid/9db409461e43ae5336c87bc8048430a1 to your computer and use it in GitHub Desktop.
Mission critical file increment helper process. Variant 3.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
James William Fletcher (github.com/mrbid) | |
August 2021 | |
Mission critical file increments. Variant 3. | |
https://james-william-fletcher.medium.com/mission-critical-integer-increment-operations-from-php-c1c71fb42451 | |
This file is compiled to a program that any | |
service can externally execute to ensure | |
a file increment or decrement operation | |
never fails. | |
Assuming that there is no condition where the | |
operating system will terminate the process | |
and that your max process limit; | |
/proc/sys/kernel/pid_max is not exceeded. | |
Integers are processed as long long with a maximum | |
value of 9223372036854775807, and are saved in string | |
format as a maximum of 19 bytes long. | |
*/ | |
#include <sys/file.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#define CHMOD 0666 | |
#define MAX_BUFF 20 // +1 for the null terminator | |
#define MAX_STRIKES 333 // total failure iterations before program exit | |
#define ALLOW_WRITE_FAIL 1 | |
int doStrikeout(const unsigned int reset) | |
{ | |
sleep(1); // sleep for 1 second between each stike | |
static unsigned int strikes = 0; | |
if(reset == 1) | |
strikes = 0; | |
strikes++; | |
if(strikes > MAX_STRIKES) | |
return 1; | |
return 0; | |
} | |
int main(int argc, char *argv[]) | |
{ | |
// check all params supplied | |
if(argc < 3) | |
{ | |
printf("Incorrect arguments.\n"); | |
return 0; | |
} | |
// temporary buffer for file read | |
char tb[MAX_BUFF] = {0}; | |
// open file | |
int f = open(argv[1], O_CREAT | O_RDWR, CHMOD); | |
doStrikeout(1); // reset strikeout | |
while(f < 0) | |
{ | |
f = open(argv[1], O_CREAT | O_RDWR, CHMOD); | |
if(doStrikeout(0) == 1) | |
goto end; | |
} | |
// lock file | |
doStrikeout(1); // reset strikeout | |
while(flock(f, LOCK_EX) < 0) | |
if(doStrikeout(0) == 1) | |
goto end; | |
// get file size in bytes | |
off_t len = lseek(f, (size_t)0, SEEK_END); | |
doStrikeout(1); // reset strikeout | |
while(len < 0) | |
{ | |
len = lseek(f, (size_t)0, SEEK_END); | |
if(doStrikeout(0) == 1) | |
goto end; | |
} | |
// check size of read fits into memory | |
// this should never fail but if it | |
// does we should exit the process or | |
// it would hang forever and eventually | |
// the system max process limit would | |
// be exceeded. | |
if(len >= MAX_BUFF) | |
{ | |
printf("len >= MAX_BUFF\n"); | |
goto end; | |
} | |
// seek back to beginning of file | |
doStrikeout(1); // reset strikeout | |
while(lseek(f, (size_t)0, SEEK_SET) < 0) | |
if(doStrikeout(0) == 1) | |
goto end; | |
// read file | |
doStrikeout(1); // reset strikeout | |
while(read(f, &tb, len) != len) | |
if(doStrikeout(0) == 1) | |
goto end; | |
// convert to long long and increment | |
const long long oll = atoll(tb); // backup encase write fails | |
long long ll = oll; | |
ll += atoll(argv[2]); | |
// set temp buff to write data | |
sprintf(tb, "%lld", ll); | |
const int wlen = strlen(tb); | |
// trunc | |
doStrikeout(1); // reset strikeout | |
while(ftruncate(f, 0) < 0) | |
if(doStrikeout(0) == 1) | |
goto end; | |
// seek | |
doStrikeout(1); // reset strikeout | |
while(lseek(f, (size_t)0, SEEK_SET) < 0) | |
if(doStrikeout(0) == 1) | |
goto end; | |
// write | |
#if ALLOW_WRITE_FAIL == 1 | |
doStrikeout(1); // reset strikeout | |
while(write(f, tb, wlen) != wlen) | |
{ | |
if(doStrikeout(0) == 1) // write has failed | |
{ | |
// try to restore original file state | |
sprintf(tb, "%lld", oll); | |
const int wlen = strlen(tb); | |
doStrikeout(1); // reset strikeout | |
while(write(f, tb, wlen) != wlen) | |
if(doStrikeout(0) == 1) | |
goto end; // catastropic failure | |
} | |
} | |
#else | |
while(write(f, tb, wlen) != wlen) | |
sleep(1); | |
#endif | |
//end | |
end: | |
// unlock | |
flock(f, LOCK_UN); | |
//done | |
fsync(f); | |
close(f); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment