cinera.c: Gracefully handle database non-creation
This commit is contained in:
parent
b3470e0f48
commit
6eeb588adf
208
cinera/cinera.c
208
cinera/cinera.c
|
@ -23,7 +23,7 @@ typedef struct
|
||||||
version CINERA_APP_VERSION = {
|
version CINERA_APP_VERSION = {
|
||||||
.Major = 0,
|
.Major = 0,
|
||||||
.Minor = 7,
|
.Minor = 7,
|
||||||
.Patch = 17
|
.Patch = 18
|
||||||
};
|
};
|
||||||
|
|
||||||
#include <stdarg.h> // NOTE(matt): varargs
|
#include <stdarg.h> // NOTE(matt): varargs
|
||||||
|
@ -4735,7 +4735,6 @@ void *
|
||||||
LocateBlock(block_id BlockID)
|
LocateBlock(block_id BlockID)
|
||||||
{
|
{
|
||||||
void *Result = 0;
|
void *Result = 0;
|
||||||
|
|
||||||
db_header *Header = (db_header *)DB.Metadata.File.Buffer.Location;
|
db_header *Header = (db_header *)DB.Metadata.File.Buffer.Location;
|
||||||
char *Ptr = (char *)Header;
|
char *Ptr = (char *)Header;
|
||||||
Ptr += sizeof(db_header);
|
Ptr += sizeof(db_header);
|
||||||
|
@ -14133,9 +14132,10 @@ WriteEntireDatabase()
|
||||||
fclose(DB.Metadata.File.Handle);
|
fclose(DB.Metadata.File.Handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
rc
|
||||||
InitDB(void)
|
InitDB(void)
|
||||||
{
|
{
|
||||||
|
rc Result = RC_SUCCESS;
|
||||||
// TODO(matt): InitDB() is called once on startup. This is correct for the .metadata file, because we only want one of
|
// TODO(matt): InitDB() is called once on startup. This is correct for the .metadata file, because we only want one of
|
||||||
// those to house the info for all projects. However, we will want to create a .index file for each project, so
|
// those to house the info for all projects. However, we will want to create a .index file for each project, so
|
||||||
// need a separate InitIndex() function that we can call when looping over the projects after ParseConfig()
|
// need a separate InitIndex() function that we can call when looping over the projects after ParseConfig()
|
||||||
|
@ -14261,7 +14261,7 @@ InitDB(void)
|
||||||
LogError(LOG_ERROR, "Unable to create directory %.*s: %s", (int)Config->DatabaseLocation.Length, Config->DatabaseLocation.Base, strerror(errno));
|
LogError(LOG_ERROR, "Unable to create directory %.*s: %s", (int)Config->DatabaseLocation.Length, Config->DatabaseLocation.Base, strerror(errno));
|
||||||
fprintf(stderr, "Unable to create directory %.*s: %s\n", (int)Config->DatabaseLocation.Length, Config->DatabaseLocation.Base, strerror(errno));
|
fprintf(stderr, "Unable to create directory %.*s: %s\n", (int)Config->DatabaseLocation.Length, Config->DatabaseLocation.Base, strerror(errno));
|
||||||
Free(DatabaseLocation0);
|
Free(DatabaseLocation0);
|
||||||
return RC_ERROR_DIRECTORY;
|
Result = RC_ERROR_DIRECTORY;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -14271,39 +14271,43 @@ InitDB(void)
|
||||||
}
|
}
|
||||||
Free(DatabaseLocation0);
|
Free(DatabaseLocation0);
|
||||||
|
|
||||||
DB.Metadata.File.Handle = fopen(DB.Metadata.File.Path, "w");
|
if(Result == RC_SUCCESS)
|
||||||
if(DB.Metadata.File.Handle)
|
|
||||||
{
|
{
|
||||||
fwrite(&DB.Header, sizeof(DB.Header), 1, DB.Metadata.File.Handle);
|
|
||||||
|
|
||||||
DB.Metadata.Signposts.ProjectsBlock.Byte = ftell(DB.Metadata.File.Handle);
|
DB.Metadata.File.Handle = fopen(DB.Metadata.File.Path, "w");
|
||||||
fwrite(&DB.ProjectsBlock, sizeof(DB.ProjectsBlock), 1, DB.Metadata.File.Handle);
|
if(DB.Metadata.File.Handle)
|
||||||
|
{
|
||||||
|
fwrite(&DB.Header, sizeof(DB.Header), 1, DB.Metadata.File.Handle);
|
||||||
|
|
||||||
DB.Metadata.Signposts.AssetsBlock.Byte = ftell(DB.Metadata.File.Handle);
|
DB.Metadata.Signposts.ProjectsBlock.Byte = ftell(DB.Metadata.File.Handle);
|
||||||
fwrite(&DB.AssetsBlock, sizeof(DB.AssetsBlock), 1, DB.Metadata.File.Handle);
|
fwrite(&DB.ProjectsBlock, sizeof(DB.ProjectsBlock), 1, DB.Metadata.File.Handle);
|
||||||
|
|
||||||
fclose(DB.Metadata.File.Handle);
|
DB.Metadata.Signposts.AssetsBlock.Byte = ftell(DB.Metadata.File.Handle);
|
||||||
ReadFileIntoBuffer(&DB.Metadata.File);
|
fwrite(&DB.AssetsBlock, sizeof(DB.AssetsBlock), 1, DB.Metadata.File.Handle);
|
||||||
DB.Metadata.Signposts.ProjectsBlock.Ptr = DB.Metadata.File.Buffer.Location + DB.Metadata.Signposts.ProjectsBlock.Byte;
|
|
||||||
DB.Metadata.Signposts.AssetsBlock.Ptr = DB.Metadata.File.Buffer.Location + DB.Metadata.Signposts.AssetsBlock.Byte;
|
fclose(DB.Metadata.File.Handle);
|
||||||
}
|
ReadFileIntoBuffer(&DB.Metadata.File);
|
||||||
else
|
DB.Metadata.Signposts.ProjectsBlock.Ptr = DB.Metadata.File.Buffer.Location + DB.Metadata.Signposts.ProjectsBlock.Byte;
|
||||||
{
|
DB.Metadata.Signposts.AssetsBlock.Ptr = DB.Metadata.File.Buffer.Location + DB.Metadata.Signposts.AssetsBlock.Byte;
|
||||||
// TODO(matt): Handle unopenable database files
|
}
|
||||||
PrintC(CS_RED, "Could not open database file: ");
|
else
|
||||||
PrintC(CS_MAGENTA_BOLD, DB.Metadata.File.Path);
|
{
|
||||||
fprintf(stderr, "\n");
|
// TODO(matt): Handle unopenable database files
|
||||||
_exit(0);
|
PrintC(CS_RED, "Could not open database file: ");
|
||||||
}
|
PrintC(CS_MAGENTA_BOLD, DB.Metadata.File.Path);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
DB.File.Handle = fopen(DB.File.Path, "w");
|
DB.File.Handle = fopen(DB.File.Path, "w");
|
||||||
fprintf(DB.File.Handle, "---\n");
|
fprintf(DB.File.Handle, "---\n");
|
||||||
fclose(DB.File.Handle);
|
fclose(DB.File.Handle);
|
||||||
ReadFileIntoBuffer(&DB.File);
|
ReadFileIntoBuffer(&DB.File);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return RC_SUCCESS;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -15340,58 +15344,63 @@ PrintEvent(struct inotify_event *Event, int EventIndex, int Indentation)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void
|
rc
|
||||||
InitAll(neighbourhood *Neighbourhood, buffers *CollationBuffers, template *BespokeTemplate)
|
InitAll(neighbourhood *Neighbourhood, buffers *CollationBuffers, template *BespokeTemplate)
|
||||||
{
|
{
|
||||||
|
rc Result = RC_SUCCESS;
|
||||||
MEM_TEST_TOP("InitAll()");
|
MEM_TEST_TOP("InitAll()");
|
||||||
RewindCollationBuffers(CollationBuffers);
|
RewindCollationBuffers(CollationBuffers);
|
||||||
/* */ MEM_TEST_MID("InitAll()");
|
/* */ MEM_TEST_MID("InitAll()");
|
||||||
/* +MEM */ InitDB();
|
/* +MEM */ Result = InitDB();
|
||||||
/* */ MEM_TEST_MID("InitAll()");
|
/* */ MEM_TEST_MID("InitAll()");
|
||||||
|
|
||||||
// TODO(matt): Straight up remove these PrintAssetsBlock() calls
|
if(Result == RC_SUCCESS)
|
||||||
//PrintAssetsBlock(0);
|
|
||||||
|
|
||||||
SyncDB(Config);
|
|
||||||
|
|
||||||
//PrintAssetsBlock(0);
|
|
||||||
|
|
||||||
|
|
||||||
printf("\n╾─ Hashing assets ─╼\n");
|
|
||||||
// NOTE(matt): This had to happen before PackTemplate() because those guys may need to do PushAsset() and we must
|
|
||||||
// ensure that the builtin assets get placed correctly
|
|
||||||
InitAssets();
|
|
||||||
PushConfiguredAssets();
|
|
||||||
//
|
|
||||||
////
|
|
||||||
|
|
||||||
PackTemplates(Neighbourhood);
|
|
||||||
|
|
||||||
bool TitledSync = FALSE;
|
|
||||||
for(int i = 0; i < Config->Project.ItemCount; ++i)
|
|
||||||
{
|
{
|
||||||
/* */ MEM_TEST_MID("InitAll()");
|
// TODO(matt): Straight up remove these PrintAssetsBlock() calls
|
||||||
/* +MEM */ SyncProject(GetPlaceInBook(&Config->Project, i), Neighbourhood, CollationBuffers, BespokeTemplate, &TitledSync);
|
//PrintAssetsBlock(0);
|
||||||
/* */ MEM_TEST_MID("InitAll()");
|
|
||||||
|
SyncDB(Config);
|
||||||
|
|
||||||
|
//PrintAssetsBlock(0);
|
||||||
|
|
||||||
|
|
||||||
|
printf("\n╾─ Hashing assets ─╼\n");
|
||||||
|
// NOTE(matt): This had to happen before PackTemplate() because those guys may need to do PushAsset() and we must
|
||||||
|
// ensure that the builtin assets get placed correctly
|
||||||
|
InitAssets();
|
||||||
|
PushConfiguredAssets();
|
||||||
|
//
|
||||||
|
////
|
||||||
|
|
||||||
|
PackTemplates(Neighbourhood);
|
||||||
|
|
||||||
|
bool TitledSync = FALSE;
|
||||||
|
for(int i = 0; i < Config->Project.ItemCount; ++i)
|
||||||
|
{
|
||||||
|
/* */ MEM_TEST_MID("InitAll()");
|
||||||
|
/* +MEM */ SyncProject(GetPlaceInBook(&Config->Project, i), Neighbourhood, CollationBuffers, BespokeTemplate, &TitledSync);
|
||||||
|
/* */ MEM_TEST_MID("InitAll()");
|
||||||
|
}
|
||||||
|
|
||||||
|
SyncGlobalPagesWithInput(Neighbourhood, CollationBuffers);
|
||||||
|
|
||||||
|
for(int i = 0; i < Assets.ItemCount; ++i)
|
||||||
|
{
|
||||||
|
UpdateAssetInDB(GetPlaceInBook(&Assets, i));
|
||||||
|
}
|
||||||
|
DeleteStaleAssets();
|
||||||
|
//PrintAssetsBlock(0);
|
||||||
|
|
||||||
|
MEM_TEST_END("InitAll()");
|
||||||
|
|
||||||
|
fprintf(stderr,
|
||||||
|
"\n"
|
||||||
|
"╾─ Monitoring file system for %snew%s, %sedited%s and %sdeleted%s .hmml and asset files ─╼\n",
|
||||||
|
ColourStrings[EditTypes[EDIT_ADDITION].Colour], ColourStrings[CS_END],
|
||||||
|
ColourStrings[EditTypes[EDIT_REINSERTION].Colour], ColourStrings[CS_END],
|
||||||
|
ColourStrings[EditTypes[EDIT_DELETION].Colour], ColourStrings[CS_END]);
|
||||||
}
|
}
|
||||||
|
return Result;
|
||||||
SyncGlobalPagesWithInput(Neighbourhood, CollationBuffers);
|
|
||||||
|
|
||||||
for(int i = 0; i < Assets.ItemCount; ++i)
|
|
||||||
{
|
|
||||||
UpdateAssetInDB(GetPlaceInBook(&Assets, i));
|
|
||||||
}
|
|
||||||
DeleteStaleAssets();
|
|
||||||
//PrintAssetsBlock(0);
|
|
||||||
|
|
||||||
MEM_TEST_END("InitAll()");
|
|
||||||
|
|
||||||
fprintf(stderr,
|
|
||||||
"\n"
|
|
||||||
"╾─ Monitoring file system for %snew%s, %sedited%s and %sdeleted%s .hmml and asset files ─╼\n",
|
|
||||||
ColourStrings[EditTypes[EDIT_ADDITION].Colour], ColourStrings[CS_END],
|
|
||||||
ColourStrings[EditTypes[EDIT_REINSERTION].Colour], ColourStrings[CS_END],
|
|
||||||
ColourStrings[EditTypes[EDIT_DELETION].Colour], ColourStrings[CS_END]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -15672,6 +15681,7 @@ void
|
||||||
Exit(void)
|
Exit(void)
|
||||||
{
|
{
|
||||||
Free(MemoryArena.Location);
|
Free(MemoryArena.Location);
|
||||||
|
fprintf(stderr, "Exiting\n");
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15812,6 +15822,7 @@ main(int ArgC, char **Args)
|
||||||
PushWatchHandle(ConfigPathL, EXT_NULL, WT_CONFIG, 0, 0);
|
PushWatchHandle(ConfigPathL, EXT_NULL, WT_CONFIG, 0, 0);
|
||||||
|
|
||||||
Config = ParseConfig(ConfigPathL, &TokensList);
|
Config = ParseConfig(ConfigPathL, &TokensList);
|
||||||
|
rc Succeeding = RC_SUCCESS;
|
||||||
if(Config)
|
if(Config)
|
||||||
{
|
{
|
||||||
if(Mode & MODE_EXAMINE)
|
if(Mode & MODE_EXAMINE)
|
||||||
|
@ -15828,7 +15839,7 @@ main(int ArgC, char **Args)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* */ MEM_TEST_MID("main()");
|
/* */ MEM_TEST_MID("main()");
|
||||||
/* +MEM */ InitAll(&Neighbourhood, &CollationBuffers, &BespokeTemplate);
|
/* +MEM */ Succeeding = InitAll(&Neighbourhood, &CollationBuffers, &BespokeTemplate);
|
||||||
/* */ MEM_TEST_MID("main()");
|
/* */ MEM_TEST_MID("main()");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15844,36 +15855,39 @@ main(int ArgC, char **Args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(inotifyInstance)
|
if(Succeeding == RC_SUCCESS)
|
||||||
{
|
{
|
||||||
while(MonitorFilesystem(&Neighbourhood, &CollationBuffers, &BespokeTemplate, ConfigPathL, &TokensList) != RC_ARENA_FULL)
|
if(inotifyInstance)
|
||||||
{
|
{
|
||||||
// TODO(matt): Refetch the quotes and rebuild player pages if needed
|
while(MonitorFilesystem(&Neighbourhood, &CollationBuffers, &BespokeTemplate, ConfigPathL, &TokensList) != RC_ARENA_FULL)
|
||||||
//
|
|
||||||
// Every sixty mins, redownload the quotes and, I suppose, SyncDBWithInput(). But here we still don't even know
|
|
||||||
// who the speaker is. To know, we'll probably have to store all quoted speakers in the project's .metadata. Maybe
|
|
||||||
// postpone this for now, but we will certainly need this to happen
|
|
||||||
//
|
|
||||||
// The most ideal solution is possibly that we store quote numbers in the Metadata->Entry, listen for and handle a
|
|
||||||
// REST PUT request from insobot when a quote changes (unless we're supposed to poll insobot for them?), and rebuild
|
|
||||||
// the player page(s) accordingly.
|
|
||||||
//
|
|
||||||
if(!(Mode & MODE_DRYRUN) && Config && Config->RespectingPrivacy && time(0) - LastPrivacyCheck > Config->PrivacyCheckInterval)
|
|
||||||
{
|
{
|
||||||
RecheckPrivacy(&Neighbourhood, &CollationBuffers, &BespokeTemplate);
|
// TODO(matt): Refetch the quotes and rebuild player pages if needed
|
||||||
|
//
|
||||||
|
// Every sixty mins, redownload the quotes and, I suppose, SyncDBWithInput(). But here we still don't even know
|
||||||
|
// who the speaker is. To know, we'll probably have to store all quoted speakers in the project's .metadata. Maybe
|
||||||
|
// postpone this for now, but we will certainly need this to happen
|
||||||
|
//
|
||||||
|
// The most ideal solution is possibly that we store quote numbers in the Metadata->Entry, listen for and handle a
|
||||||
|
// REST PUT request from insobot when a quote changes (unless we're supposed to poll insobot for them?), and rebuild
|
||||||
|
// the player page(s) accordingly.
|
||||||
|
//
|
||||||
|
if(!(Mode & MODE_DRYRUN) && Config && Config->RespectingPrivacy && time(0) - LastPrivacyCheck > Config->PrivacyCheckInterval)
|
||||||
|
{
|
||||||
|
RecheckPrivacy(&Neighbourhood, &CollationBuffers, &BespokeTemplate);
|
||||||
|
}
|
||||||
|
sleep(GLOBAL_UPDATE_INTERVAL);
|
||||||
}
|
}
|
||||||
sleep(GLOBAL_UPDATE_INTERVAL);
|
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
else
|
{
|
||||||
{
|
fprintf(stderr, "Error: Quitting because inotify initialisation failed with message\n"
|
||||||
fprintf(stderr, "Error: Quitting because inotify initialisation failed with message\n"
|
" %s\n", strerror(inotifyError));
|
||||||
" %s\n", strerror(inotifyError));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
DiscardAllAndFreeConfig();
|
DiscardAllAndFreeConfig();
|
||||||
RemoveAndFreeWatchHandles(&WatchHandles);
|
RemoveAndFreeWatchHandles(&WatchHandles);
|
||||||
MEM_TEST_END("main()");
|
MEM_TEST_END("main()");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Exit();
|
Exit();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue