From de2c6328065360c8568eb28eb5d0566dc38e2673 Mon Sep 17 00:00:00 2001 From: Matt Mascarenhas Date: Tue, 6 Mar 2018 20:40:12 +0000 Subject: [PATCH] cinera.c: Binary search the .metadata Also optimise out superfluous searches, and relieve IndexToBuffer() of the need to string-search the .index Rewrite the table of contents page after deleting an entry This commit also retains profiling, as a reminder to me how I used it, and the old linear search code. The timing blocks and the old code may be deleted in a future commit --- cinera/cinera.c | 316 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 242 insertions(+), 74 deletions(-) diff --git a/cinera/cinera.c b/cinera/cinera.c index b38c353..b8d6f3b 100644 --- a/cinera/cinera.c +++ b/cinera/cinera.c @@ -14,20 +14,21 @@ typedef struct version CINERA_APP_VERSION = { .Major = 0, .Minor = 5, - .Patch = 37 + .Patch = 38 }; // TODO(matt): Copy in the DB 3 stuff from cinera_working.c #define CINERA_DB_VERSION 3 -#define DEBUG 0 -#define DEBUG_MEM 0 - typedef unsigned int bool; - #define TRUE 1 #define FALSE 0 +#define DEBUG 0 +#define DEBUG_MEM 0 +#define BINARY_SEARCH 1 +bool PROFILING = 0; + #include // NOTE(matt): varargs #include // NOTE(matt): printf, sprintf, vsprintf, fprintf, perror #include // NOTE(matt): calloc, malloc, free @@ -44,6 +45,10 @@ typedef unsigned int bool; #include // NOTE(matt): inotify #include // NOTE(matt): sleep() +clock_t TIMING_START; +#define START_TIMING_BLOCK(...) if(PROFILING) { printf(__VA_ARGS__); TIMING_START = clock(); } +#define END_TIMING_BLOCK() if(PROFILING) { printf("\e[1;34m%ld\e[0m\n", clock() - TIMING_START);} + #define Kilobytes(Bytes) Bytes << 10 #define Megabytes(Bytes) Bytes << 20 @@ -880,11 +885,17 @@ DeclaimBuffer(buffer *Buffer) MemoryArena.Ptr - MemoryArena.Location); #endif LogUsage(Buffer); - if(PercentageUsed >= 80.0f) + if(PercentageUsed >= 95.0f) { // TODO(matt): Implement either dynamically growing buffers, or phoning home to matt@handmadedev.org LogError(LOG_ERROR, "%s used %.2f%% of its allotted memory\n", Buffer->ID, PercentageUsed); - fprintf(stderr, "Warning: %s used %.2f%% of its allotted memory\n", Buffer->ID, PercentageUsed); + fprintf(stderr, "\e[1;31mWarning\e[0m: %s used %.2f%% of its allotted memory\n", Buffer->ID, PercentageUsed); + } + else if(PercentageUsed >= 80.0f) + { + // TODO(matt): Implement either dynamically growing buffers, or phoning home to matt@handmadedev.org + LogError(LOG_ERROR, "%s used %.2f%% of its allotted memory\n", Buffer->ID, PercentageUsed); + fprintf(stderr, "\e[0;33mWarning\e[0m: %s used %.2f%% of its allotted memory\n", Buffer->ID, PercentageUsed); } Buffer->Size = 0; } @@ -2916,7 +2927,7 @@ HMMLToBuffers(buffers *CollationBuffers, template **BespokeTemplate, char *Filen if(ClaimBuffer(&AnnotationClass, "AnnotationClass", 256) == RC_ARENA_FULL) { hmml_free(&HMML); return RC_ARENA_FULL; }; if(ClaimBuffer(&AnnotationData, "AnnotationData", 512) == RC_ARENA_FULL) { hmml_free(&HMML); return RC_ARENA_FULL; }; if(ClaimBuffer(&Text, "Text", Kilobytes(4)) == RC_ARENA_FULL) { hmml_free(&HMML); return RC_ARENA_FULL; }; - if(ClaimBuffer(&CategoryIcons, "CategoryIcons", 512) == RC_ARENA_FULL) { hmml_free(&HMML); return RC_ARENA_FULL; }; + if(ClaimBuffer(&CategoryIcons, "CategoryIcons", Kilobytes(1)) == RC_ARENA_FULL) { hmml_free(&HMML); return RC_ARENA_FULL; }; CopyStringToBuffer(&AnnotationHeader, "
Metadata.Buffer.Ptr + sizeof(index_metadata) * Lower); + if(StringsDiffer(SearchTerm, LowerEntry->BaseFilename) < 0 ) { return Lower; } + + int Upper = Index->Header.EntryCount - 1; + int Pivot = Upper - ((Upper - Lower) >> 1); + index_metadata *UpperEntry; + index_metadata *PivotEntry; + + do { + LowerEntry = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * Lower); + PivotEntry = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * Pivot); + UpperEntry = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * Upper); + + if(!StringsDiffer(SearchTerm, LowerEntry->BaseFilename)) { *Test = LowerEntry; return Lower; } + if(!StringsDiffer(SearchTerm, PivotEntry->BaseFilename)) { *Test = PivotEntry; return Pivot; } + if(!StringsDiffer(SearchTerm, UpperEntry->BaseFilename)) { *Test = UpperEntry; return Upper; } + + if((StringsDiffer(SearchTerm, PivotEntry->BaseFilename) < 0)) { Upper = Pivot; } + else { Lower = Pivot; } + Pivot = Upper - ((Upper - Lower) >> 1); + } while(Upper > Pivot); + return Upper; +} + +int +AccumulateIndexEntryInsertionOffset(index *Index, int EntryIndex) +{ + int Result = 0; + index_metadata *AccEntry = { 0 }; + if(EntryIndex < Index->Header.EntryCount >> 1) + { + for(; EntryIndex > 0; --EntryIndex) + { + AccEntry = (index_metadata*)(Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * (EntryIndex - 1)); + Result += AccEntry->Size; + } + Result += StringLength("---\n"); + } + else + { + for(; EntryIndex < Index->Header.EntryCount; ++EntryIndex) + { + AccEntry = (index_metadata*)(Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * EntryIndex); + Result += AccEntry->Size; + } + Result = Index->File.FileSize - Result; + } + return Result; +} + +int +InsertIntoIndex(index *Index, int *EntryIndex, buffers *CollationBuffers, template **BespokeTemplate, char *BaseFilename) { int IndexMetadataFileReadCode = ReadFileIntoBuffer(&Index->Metadata, 0); switch(IndexMetadataFileReadCode) @@ -4399,12 +4464,11 @@ InsertIntoIndex(index *Index, buffers *CollationBuffers, template **BespokeTempl int IndexEntryInsertionStart = -1; int IndexEntryInsertionEnd = -1; Index->Header.EntryCount = 0; - char *IndexEntryStart; bool Found = FALSE; - int EntryIndex; neighbours Neighbours = { 0 }; - index_metadata *This, *Next; + index_metadata *This = { 0 }; + index_metadata *Next = { 0 }; if(IndexMetadataFileReadCode == RC_SUCCESS && IndexFileReadCode == RC_SUCCESS) { // TODO(matt): Index validation? @@ -4421,15 +4485,70 @@ InsertIntoIndex(index *Index, buffers *CollationBuffers, template **BespokeTempl Index->Metadata.Buffer.Ptr += sizeof(Index->Header); Index->File.Buffer.Ptr += StringLength("---\n"); - IndexEntryStart = Index->File.Buffer.Ptr; - for(EntryIndex = 0; EntryIndex < Index->Header.EntryCount; ++EntryIndex) +#if BINARY_SEARCH +START_TIMING_BLOCK(" InsertIntoIndex(%s) BinarySearch: ", BaseFilename); + index_metadata *Prev = { 0 }; + *EntryIndex = BinarySearchForMetadataEntry(Index, &This, BaseFilename); + if(This) + { + // Reinsert + Found = TRUE; + MetadataInsertionOffset = sizeof(index_header) + sizeof(index_metadata) * *EntryIndex; + IndexEntryInsertionStart = AccumulateIndexEntryInsertionOffset(Index, *EntryIndex); + IndexEntryInsertionEnd = IndexEntryInsertionStart + This->Size; + if(*EntryIndex > 0) + { + Prev = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * (*EntryIndex - 1)); + Neighbours.Prev.BaseFilename = Prev->BaseFilename; + Neighbours.Prev.Title = Prev->Title; + } + if(*EntryIndex < Index->Header.EntryCount - 1) + { + Next = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * (*EntryIndex + 1)); + Neighbours.Next.BaseFilename = Next->BaseFilename; + Neighbours.Next.Title = Next->Title; + } + } + else + { + This = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * *EntryIndex); + if(StringsDiffer(BaseFilename, This->BaseFilename) < 0) + { + // Insert + MetadataInsertionOffset = sizeof(index_header) + sizeof(index_metadata) * *EntryIndex; + IndexEntryInsertionStart = AccumulateIndexEntryInsertionOffset(Index, *EntryIndex); + if(*EntryIndex > 0) + { + Prev = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * (*EntryIndex - 1)); + Neighbours.Prev.BaseFilename = Prev->BaseFilename; + Neighbours.Prev.Title = Prev->Title; + } + Neighbours.Next.BaseFilename = This->BaseFilename; + Neighbours.Next.Title = This->Title; + } + else + { + // Append + if(*EntryIndex > 0) + { + Neighbours.Prev.BaseFilename = This->BaseFilename; + Neighbours.Prev.Title = This->Title; + } + ++*EntryIndex; + } + } +#else +START_TIMING_BLOCK(" InsertIntoIndex(%s) LinearSearch: ", BaseFilename); + char *IndexEntryStart; + IndexEntryStart = Index->File.Buffer.Ptr; + for(*EntryIndex = 0; *EntryIndex < Index->Header.EntryCount; ++*EntryIndex) { This = (index_metadata *)Index->Metadata.Buffer.Ptr; if(!StringsDiffer(This->BaseFilename, BaseFilename)) { // Reinsert - if(EntryIndex < (Index->Header.EntryCount - 1)) + if(*EntryIndex < (Index->Header.EntryCount - 1)) { Next = (index_metadata *)(Index->Metadata.Buffer.Ptr + sizeof(Index->Entry)); Neighbours.Next.BaseFilename = Next->BaseFilename; @@ -4463,9 +4582,11 @@ InsertIntoIndex(index *Index, buffers *CollationBuffers, template **BespokeTempl Neighbours.Prev.Title = This->Title; } } +#endif } else { +START_TIMING_BLOCK(" InsertIntoIndex(%s) NoSearch: ", BaseFilename); // NOTE(matt): Initialising new index_header Index->Header.CurrentDBVersion = CINERA_DB_VERSION; Index->Header.CurrentAppVersion = CINERA_APP_VERSION; @@ -4507,6 +4628,7 @@ InsertIntoIndex(index *Index, buffers *CollationBuffers, template **BespokeTempl } closedir(OutputDirectoryHandle); } +END_TIMING_BLOCK(); char InputFile[StringLength(BaseFilename) + StringLength(".hmml")]; CopyString(InputFile, "%s.hmml", BaseFilename); @@ -4783,7 +4905,7 @@ int DeleteNeighbourLinks(file_buffer *File, index_metadata *Metadata) } } -int LinkNeighbours(index *Index, char *BaseFilename, int LinkType) +int LinkNeighbours(index *Index, int EntryIndex, char *BaseFilename, int LinkType) { switch(ReadFileIntoBuffer(&Index->Metadata, 0)) { @@ -4801,8 +4923,24 @@ int LinkNeighbours(index *Index, char *BaseFilename, int LinkType) index_metadata *Prev = { 0 }; index_metadata *This = { 0 }; index_metadata *Next = { 0 }; - int EntryIndex = 0; +#if BINARY_SEARCH +START_TIMING_BLOCK(" LinkNeighbours(%s) [passing in EntryIndex]: ", BaseFilename); + This = (index_metadata *)Index->Metadata.Buffer.Ptr; + if(Index->Header.EntryCount != 1) + { + This = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * EntryIndex); + if(EntryIndex > 0) + { + Prev = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * (EntryIndex - 1)); + } + if(EntryIndex < Index->Header.EntryCount - 1) + { + Next = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * (EntryIndex + 1)); + } + } +#else +START_TIMING_BLOCK(" LinkNeighbours(%s) LinearSearch: ", BaseFilename); switch(LinkType) { case LINK_INCLUDE: @@ -4848,6 +4986,8 @@ int LinkNeighbours(index *Index, char *BaseFilename, int LinkType) } } break; } +#endif +END_TIMING_BLOCK(); if(!Prev && !Next) { @@ -4953,7 +5093,7 @@ int LinkNeighbours(index *Index, char *BaseFilename, int LinkType) } int -DeleteFromIndex(index *Index, char *BaseFilename) +DeleteFromIndex(index *Index, int *EntryIndex, char *BaseFilename) { // TODO(matt): LogError() switch(ReadFileIntoBuffer(&Index->Metadata, 0)) @@ -4985,9 +5125,23 @@ DeleteFromIndex(index *Index, char *BaseFilename) int DeleteMetadataFrom = -1; int DeleteFileFrom = -1; int DeleteFileTo = -1; - int SizeAcc = 0; - for(int EntryIndex = 0; EntryIndex < Index->Header.EntryCount; ++EntryIndex, Index->Metadata.Buffer.Ptr += sizeof(index_metadata)) +#if BINARY_SEARCH +START_TIMING_BLOCK(" DeleteFromIndex(%s) BinarySearch: ", BaseFilename); + index_metadata *This = { 0 }; + *EntryIndex = BinarySearchForMetadataEntry(Index, &This, BaseFilename); + if(This) + { + Found = TRUE; + DeleteMetadataFrom = (char *)This - Index->Metadata.Buffer.Location; + DeleteFileFrom = AccumulateIndexEntryInsertionOffset(Index, *EntryIndex); + DeleteFileTo = DeleteFileFrom + This->Size; + --Index->Header.EntryCount; + } +#else +START_TIMING_BLOCK(" DeleteFromIndex(%s) LinearSearch: ", BaseFilename); + int SizeAcc = 0; + for(*EntryIndex = 0; *EntryIndex < Index->Header.EntryCount; ++*EntryIndex, Index->Metadata.Buffer.Ptr += sizeof(index_metadata)) { index_metadata This = *(index_metadata *)Index->Metadata.Buffer.Ptr; if(!StringsDiffer(This.BaseFilename, BaseFilename)) @@ -5001,6 +5155,9 @@ DeleteFromIndex(index *Index, char *BaseFilename) } SizeAcc += This.Size; } +#endif +END_TIMING_BLOCK(); + if(Found) { @@ -5019,6 +5176,11 @@ DeleteFromIndex(index *Index, char *BaseFilename) } else { + if(*EntryIndex == Index->Header.EntryCount) // NOTE(matt): LinkNeighbours() requires this + { + --*EntryIndex; + } + if(!(Index->Metadata.Handle = fopen(Index->Metadata.Path, "w"))) { FreeBuffer(&Index->Metadata.Buffer); return RC_ERROR_FILE; } if(!(Index->File.Handle = fopen(Index->File.Path, "w"))) { FreeBuffer(&Index->File.Buffer); return RC_ERROR_FILE; } @@ -5043,18 +5205,10 @@ DeleteFromIndex(index *Index, char *BaseFilename) int IndexToBuffer(index *Index, buffers *CollationBuffers) // NOTE(matt): This guy malloc's CollationBuffers->Index { - // TODO(matt): Consider parsing the index into a linked / skip list, or do something to save us having to iterate through - // the index file multiple times - - int IndexMetadataFileReadCode = ReadFileIntoBuffer(&Index->Metadata, 0); - int IndexFileReadCode = ReadFileIntoBuffer(&Index->File, 0); - - if(IndexMetadataFileReadCode == RC_SUCCESS && IndexFileReadCode == RC_SUCCESS) + if(ReadFileIntoBuffer(&Index->Metadata, 0) == RC_SUCCESS) { Index->Header = *(index_header*)Index->Metadata.Buffer.Ptr; Index->Metadata.Buffer.Ptr += sizeof(Index->Header); - Index->File.Buffer.Ptr += StringLength("---\n"); - char *IndexEntryStart = Index->File.Buffer.Ptr; bool ProjectFound = FALSE; int ProjectIndex; @@ -5071,12 +5225,12 @@ IndexToBuffer(index *Index, buffers *CollationBuffers) // NOTE(matt): This guy m { fprintf(stderr, "Missing Project Info for %s\n", Config.ProjectID); FreeBuffer(&Index->Metadata.Buffer); - FreeBuffer(&Index->File.Buffer); return RC_ERROR_PROJECT; } - int ThemeStringLength = StringsDiffer(Config.Theme, "") ? (StringLength(Config.Theme) * 2) : (StringLength(Config.ProjectID) * 2); - char queryContainer[680 + ThemeStringLength]; + char *Theme = StringsDiffer(Config.Theme, "") ? Config.Theme : Config.ProjectID; + int ThemeStringAllowance = StringLength(Theme) * 2; + char queryContainer[680 + ThemeStringAllowance]; CopyString(queryContainer, "
\n" " \n" @@ -5093,8 +5247,8 @@ IndexToBuffer(index *Index, buffers *CollationBuffers) // NOTE(matt): This guy m "
\n" "
Sort: Old to New ⏶
\n" "
\n", - StringsDiffer(Config.Theme, "") ? Config.Theme : Config.ProjectID, - StringsDiffer(Config.Theme, "") ? Config.Theme : Config.ProjectID); + Theme, + Theme); buffer URLPrefix; ClaimBuffer(&URLPrefix, "URLPrefix", 1024); @@ -5118,7 +5272,7 @@ IndexToBuffer(index *Index, buffers *CollationBuffers) // NOTE(matt): This guy m " \n" " \n", Config.ProjectID, - StringsDiffer(Config.Theme, "") ? Config.Theme : Config.ProjectID, + Theme, Config.BaseURL, Config.PlayerLocation, StringsDiffer(Config.PlayerURLPrefix, "") ? Config.PlayerURLPrefix : Config.ProjectID, @@ -5132,18 +5286,26 @@ IndexToBuffer(index *Index, buffers *CollationBuffers) // NOTE(matt): This guy m if(!(CollationBuffers->Index.Location = malloc(CollationBuffers->Index.Size))) { FreeBuffer(&Index->Metadata.Buffer); - FreeBuffer(&Index->File.Buffer); return(RC_ERROR_MEMORY); } CollationBuffers->Index.Ptr = CollationBuffers->Index.Location; CopyStringToBuffer(&CollationBuffers->Index, queryContainer); - for(int EntryIndex = 0; EntryIndex < Index->Header.EntryCount; ++EntryIndex) + char *ProjectUnit = 0; + if(StringsDiffer(ProjectInfo[ProjectIndex].Unit, "")) { - index_metadata This = *(index_metadata *)Index->Metadata.Buffer.Ptr; - char Number[16]; - CopyString(Number, This.BaseFilename + StringLength(Config.ProjectID)); + ProjectUnit = ProjectInfo[ProjectIndex].Unit; + } + int ProjectIDLength = StringLength(Config.ProjectID); + char Number[16]; + char Text[1024]; // NOTE(matt): Surely this will be big enough + index_metadata *This; + + for(int EntryIndex = 0; EntryIndex < Index->Header.EntryCount; ++EntryIndex, Index->Metadata.Buffer.Ptr += sizeof(index_metadata)) + { + This = (index_metadata *)Index->Metadata.Buffer.Ptr; + CopyString(Number, This->BaseFilename + ProjectIDLength); if(ProjectInfo[ProjectIndex].NumberingScheme == NS_LINEAR) { for(int i = 0; Number[i]; ++i) @@ -5155,24 +5317,18 @@ IndexToBuffer(index *Index, buffers *CollationBuffers) // NOTE(matt): This guy m } } - SeekBufferForString(&Index->File.Buffer, "title: \"", C_SEEK_FORWARDS, C_SEEK_AFTER); - char Title[256]; - CopyStringNoFormatT(Title, Index->File.Buffer.Ptr, '\n'); - Title[StringLength(Title) - 1] = '\0'; + ConstructPlayerURL(&PlayerURL, This->BaseFilename); - ConstructPlayerURL(&PlayerURL, This.BaseFilename); - - if(StringsDiffer(ProjectInfo[ProjectIndex].Unit, "")) + if(ProjectUnit) { CopyStringToBuffer(&CollationBuffers->Index, "
\n" " ", PlayerURL.Location); - char Text[1024]; // NOTE(matt): Surely this will be big enough CopyString(Text, "%s %s: %s", - ProjectInfo[ProjectIndex].Unit, // TODO(matt): Do we need to special-case the various numbering schemes? + ProjectUnit, // TODO(matt): Do we need to special-case the various numbering schemes? Number, - Title); + This->Title); CopyStringToBufferHTMLSafe(&CollationBuffers->Index, Text); @@ -5184,15 +5340,13 @@ IndexToBuffer(index *Index, buffers *CollationBuffers) // NOTE(matt): This guy m { CopyStringToBuffer(&CollationBuffers->Index, "
\n" - " %s\n" - "
\n", - PlayerURL.Location, - Title); - } + " ", PlayerURL.Location); - Index->Metadata.Buffer.Ptr += sizeof(Index->Entry); - IndexEntryStart += This.Size; - Index->File.Buffer.Ptr = IndexEntryStart; + CopyStringToBufferHTMLSafe(&CollationBuffers->Index, This->Title); + CopyStringToBuffer(&CollationBuffers->Index, + "\n" + "
\n"); + } } DeclaimBuffer(&PlayerURL); @@ -5200,7 +5354,6 @@ IndexToBuffer(index *Index, buffers *CollationBuffers) // NOTE(matt): This guy m CopyStringToBuffer(&CollationBuffers->Index, Script); FreeBuffer(&Index->Metadata.Buffer); - FreeBuffer(&Index->File.Buffer); return RC_SUCCESS; } else @@ -5242,7 +5395,7 @@ StripSurroundingSlashes(char *String) // NOTE(matt): For relative paths } int -GeneratePlayerPage(index *Index, buffers *CollationBuffers, template *PlayerTemplate, char *BaseFilename) +GeneratePlayerPage(index *Index, int EntryIndex, buffers *CollationBuffers, template *PlayerTemplate, char *BaseFilename) { buffer OutputDirectoryPath; ClaimBuffer(&OutputDirectoryPath, "OutputDirectoryPath", 1024); @@ -5281,7 +5434,12 @@ GeneratePlayerPage(index *Index, buffers *CollationBuffers, template *PlayerTemp ReadFileIntoBuffer(&Index->Metadata, 0); Index->Metadata.Buffer.Ptr += sizeof(index_header); int MetadataInsertionOffset = 0; - for(int EntryIndex = 0; EntryIndex < Index->Header.EntryCount; ++EntryIndex) +#if BINARY_SEARCH +START_TIMING_BLOCK(" GeneratePlayerPage(%s) [passing in EntryIndex]: ", BaseFilename); + MetadataInsertionOffset = sizeof(index_header) + sizeof(index_metadata) * EntryIndex; +#else +START_TIMING_BLOCK(" GeneratePlayerPage(%s) LinearSearch: ", BaseFilename); + for(EntryIndex = 0; EntryIndex < Index->Header.EntryCount; ++EntryIndex) { index_metadata This = *(index_metadata *)Index->Metadata.Buffer.Ptr; if(!StringsDiffer(This.BaseFilename, Index->Entry.BaseFilename)) @@ -5291,11 +5449,13 @@ GeneratePlayerPage(index *Index, buffers *CollationBuffers, template *PlayerTemp } Index->Metadata.Buffer.Ptr += sizeof(index_metadata); } +#endif +END_TIMING_BLOCK(); if(!(Index->Metadata.Handle = fopen(Index->Metadata.Path, "w"))) { FreeBuffer(&Index->Metadata.Buffer); return RC_ERROR_FILE; } fwrite(Index->Metadata.Buffer.Location, MetadataInsertionOffset, 1, Index->Metadata.Handle); fwrite(&Index->Entry, sizeof(Index->Entry), 1, Index->Metadata.Handle); - fwrite(Index->Metadata.Buffer.Ptr + sizeof(Index->Entry), Index->Metadata.FileSize - MetadataInsertionOffset - sizeof(Index->Entry), 1, Index->Metadata.Handle); + fwrite(Index->Metadata.Buffer.Location + MetadataInsertionOffset + sizeof(Index->Entry), Index->Metadata.FileSize - MetadataInsertionOffset - sizeof(Index->Entry), 1, Index->Metadata.Handle); fclose(Index->Metadata.Handle); FreeBuffer(&Index->Metadata.Buffer); @@ -5374,14 +5534,17 @@ DeletePlayerPageFromFilesystem(char *BaseFilename, char *PlayerLocation, bool Re return RC_SUCCESS; } -void +int DeleteEntry(index *Index, char *BaseFilename) { - if(DeleteFromIndex(Index, BaseFilename) == RC_SUCCESS) + int EntryIndex = 0; + if(DeleteFromIndex(Index, &EntryIndex, BaseFilename) == RC_SUCCESS) { - LinkNeighbours(Index, BaseFilename, LINK_EXCLUDE); + LinkNeighbours(Index, EntryIndex, BaseFilename, LINK_EXCLUDE); DeletePlayerPageFromFilesystem(BaseFilename, Config.PlayerLocation, FALSE); + return RC_SUCCESS; } + return RC_NOOP; } int @@ -5419,24 +5582,28 @@ MonitorDirectory(index *Index, buffers *CollationBuffers, template *IndexTemplat // TODO(matt): Maybe handle IN_ALL_EVENTS if(Event->mask & IN_DELETE || Event->mask & IN_MOVED_FROM) { - DeleteEntry(Index, BaseFilename); + if(DeleteEntry(Index, BaseFilename) == RC_SUCCESS) + { + GenerateIndexPage(Index, CollationBuffers, IndexTemplate); + } } else { - switch(InsertIntoIndex(Index, CollationBuffers, &BespokeTemplate, BaseFilename)) + int EntryIndex = 0; + switch(InsertIntoIndex(Index, &EntryIndex, CollationBuffers, &BespokeTemplate, BaseFilename)) { case RC_SUCCESS: case RC_UNFOUND: - LinkNeighbours(Index, BaseFilename, LINK_INCLUDE); + LinkNeighbours(Index, EntryIndex, BaseFilename, LINK_INCLUDE); { if(BespokeTemplate->Metadata.Filename && StringsDiffer(BespokeTemplate->Metadata.Filename, "")) { - GeneratePlayerPage(Index, CollationBuffers, BespokeTemplate, BaseFilename); + GeneratePlayerPage(Index, EntryIndex, CollationBuffers, BespokeTemplate, BaseFilename); DeclaimTemplate(BespokeTemplate); } else { - GeneratePlayerPage(Index, CollationBuffers, PlayerTemplate, BaseFilename); + GeneratePlayerPage(Index, EntryIndex, CollationBuffers, PlayerTemplate, BaseFilename); } GenerateIndexPage(Index, CollationBuffers, IndexTemplate); } break; @@ -5804,20 +5971,21 @@ SyncIndexWithInput(index *Index, buffers *CollationBuffers, template *IndexTempl if(!(StringsDiffer(Ptr, ".hmml"))) { *Ptr = '\0'; - switch(InsertIntoIndex(Index, CollationBuffers, &BespokeTemplate, ProjectFiles->d_name)) + int EntryIndex = 0; + switch(InsertIntoIndex(Index, &EntryIndex, CollationBuffers, &BespokeTemplate, ProjectFiles->d_name)) { case RC_UNFOUND: - LinkNeighbours(Index, ProjectFiles->d_name, LINK_INCLUDE); + LinkNeighbours(Index, EntryIndex, ProjectFiles->d_name, LINK_INCLUDE); case RC_SUCCESS: { if(BespokeTemplate->Metadata.Filename && StringsDiffer(BespokeTemplate->Metadata.Filename, "")) { - GeneratePlayerPage(Index, CollationBuffers, BespokeTemplate, ProjectFiles->d_name); + GeneratePlayerPage(Index, EntryIndex, CollationBuffers, BespokeTemplate, ProjectFiles->d_name); DeclaimTemplate(BespokeTemplate); } else { - GeneratePlayerPage(Index, CollationBuffers, PlayerTemplate, ProjectFiles->d_name); + GeneratePlayerPage(Index, EntryIndex, CollationBuffers, PlayerTemplate, ProjectFiles->d_name); } Inserted = TRUE; }