Only load tracks if cache is invalid

This commit is contained in:
Ted John 2016-10-23 01:12:17 +01:00
parent 9eaf887546
commit 712e062bcc
4 changed files with 132 additions and 47 deletions

View File

@ -57,6 +57,7 @@ struct DirectoryChild
uint64 LastModified; uint64 LastModified;
}; };
static uint32 GetPathChecksum(const utf8 * path);
static bool MatchWildcard(const utf8 * fileName, const utf8 * pattern); static bool MatchWildcard(const utf8 * fileName, const utf8 * pattern);
class FileScannerBase : public IFileScanner class FileScannerBase : public IFileScanner
@ -363,6 +364,40 @@ IFileScanner * Path::ScanDirectory(const utf8 * pattern, bool recurse)
#endif #endif
} }
void Path::QueryDirectory(QueryDirectoryResult * result, const utf8 * pattern)
{
IFileScanner * scanner = Path::ScanDirectory(pattern, true);
while (scanner->Next())
{
const FileInfo * fileInfo = scanner->GetFileInfo();
const utf8 * path = scanner->GetPath();
result->TotalFiles++;
result->TotalFileSize += fileInfo->Size;
result->FileDateModifiedChecksum ^=
(uint32)(fileInfo->LastModified >> 32) ^
(uint32)(fileInfo->LastModified & 0xFFFFFFFF);
result->FileDateModifiedChecksum = ror32(result->FileDateModifiedChecksum, 5);
result->PathChecksum += GetPathChecksum(path);
}
delete scanner;
}
static uint32 GetPathChecksum(const utf8 * path)
{
uint32 hash = 0xD8430DED;
for (const utf8 * ch = path; *ch != '\0'; ch++)
{
hash += (*ch);
hash += (hash << 10);
hash ^= (hash >> 6);
}
hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);
return hash;
}
/** /**
* Due to FindFirstFile / FindNextFile searching for DOS names as well, *.doc also matches *.docx which isn't what the pattern * Due to FindFirstFile / FindNextFile searching for DOS names as well, *.doc also matches *.docx which isn't what the pattern
* specified. This will verify if a filename does indeed match the pattern we asked for. * specified. This will verify if a filename does indeed match the pattern we asked for.

View File

@ -41,7 +41,30 @@ interface IFileScanner
virtual bool Next() abstract; virtual bool Next() abstract;
}; };
struct QueryDirectoryResult
{
uint32 TotalFiles;
uint64 TotalFileSize;
uint32 FileDateModifiedChecksum;
uint32 PathChecksum;
};
namespace Path namespace Path
{ {
/**
* Scans a directory and optionally sub directories for files that matches the
* given pattern and returns an enumerator.
* @param pattern The path followed by a semi-colon delimited list of wildcard patterns.
* @param recurse Whether to scan sub directories or not.
* @returns A new FileScanner, this must be deleted when no longer needed.
*/
IFileScanner * ScanDirectory(const utf8 * pattern, bool recurse); IFileScanner * ScanDirectory(const utf8 * pattern, bool recurse);
/**
* Scans a directory and all sub directories
* @param result The query result to modify.
* @param pattern The path followed by a semi-colon delimited list of wildcard patterns.
* @returns An aggregated result of all scanned files.
*/
void QueryDirectory(QueryDirectoryResult * result, const utf8 * pattern);
} }

View File

@ -46,7 +46,7 @@ extern "C"
#include "../object_list.h" #include "../object_list.h"
#include "../platform/platform.h" #include "../platform/platform.h"
#include "../util/sawyercoding.h" #include "../util/sawyercoding.h"
#include "../util/util.h" #include "../util/util.h"
} }
constexpr uint16 OBJECT_REPOSITORY_VERSION = 10; constexpr uint16 OBJECT_REPOSITORY_VERSION = 10;
@ -65,14 +65,6 @@ struct ObjectRepositoryHeader
assert_struct_size(ObjectRepositoryHeader, 28); assert_struct_size(ObjectRepositoryHeader, 28);
#pragma pack(pop) #pragma pack(pop)
struct QueryDirectoryResult
{
uint32 TotalFiles;
uint64 TotalFileSize;
uint32 FileDateModifiedChecksum;
uint32 PathChecksum;
};
struct ObjectEntryHash struct ObjectEntryHash
{ {
size_t operator()(const rct_object_entry &entry) const size_t operator()(const rct_object_entry &entry) const
@ -239,22 +231,7 @@ private:
utf8 pattern[MAX_PATH]; utf8 pattern[MAX_PATH];
String::Set(pattern, sizeof(pattern), directory); String::Set(pattern, sizeof(pattern), directory);
Path::Append(pattern, sizeof(pattern), "*.dat"); Path::Append(pattern, sizeof(pattern), "*.dat");
Path::QueryDirectory(result, pattern);
IFileScanner * scanner = Path::ScanDirectory(pattern, true);
while (scanner->Next())
{
const FileInfo * fileInfo = scanner->GetFileInfo();
const utf8 * path = scanner->GetPath();
result->TotalFiles++;
result->TotalFileSize += fileInfo->Size;
result->FileDateModifiedChecksum ^=
(uint32)(fileInfo->LastModified >> 32) ^
(uint32)(fileInfo->LastModified & 0xFFFFFFFF);
result->FileDateModifiedChecksum = ror32(result->FileDateModifiedChecksum, 5);
result->PathChecksum += GetPathChecksum(path);
}
delete scanner;
} }
void Construct() void Construct()
@ -650,21 +627,6 @@ private:
{ {
platform_get_user_directory(buffer, "object", bufferSize); platform_get_user_directory(buffer, "object", bufferSize);
} }
static uint32 GetPathChecksum(const utf8 * path)
{
uint32 hash = 0xD8430DED;
for (const utf8 * ch = path; *ch != '\0'; ch++)
{
hash += (*ch);
hash += (hash << 10);
hash ^= (hash >> 6);
}
hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);
return hash;
}
}; };
static std::unique_ptr<ObjectRepository> _objectRepository; static std::unique_ptr<ObjectRepository> _objectRepository;

View File

@ -35,6 +35,10 @@ struct TrackRepositoryHeader
{ {
uint32 MagicNumber; uint32 MagicNumber;
uint16 Version; uint16 Version;
uint32 TotalFiles;
uint64 TotalFileSize;
uint32 FileDateModifiedChecksum;
uint32 PathChecksum;
uint32 NumItems; uint32 NumItems;
}; };
#pragma pack(pop) #pragma pack(pop)
@ -60,6 +64,7 @@ class TrackDesignRepository : public ITrackDesignRepository
{ {
private: private:
std::vector<TrackRepositoryItem> _items; std::vector<TrackRepositoryItem> _items;
QueryDirectoryResult _directoryQueryResult;
public: public:
virtual ~TrackDesignRepository() virtual ~TrackDesignRepository()
@ -111,16 +116,24 @@ public:
void Scan() override void Scan() override
{ {
utf8 directory[MAX_PATH]; utf8 rct2Directory[MAX_PATH];
utf8 userDirectory[MAX_PATH];
GetRCT2Directory(directory, sizeof(directory)); GetRCT2Directory(rct2Directory, sizeof(rct2Directory));
Scan(directory, TRIF_READ_ONLY); GetUserDirectory(userDirectory, sizeof(userDirectory));
GetUserDirectory(directory, sizeof(directory)); _items.clear();
Scan(directory); _directoryQueryResult = { 0 };
Query(rct2Directory);
Query(userDirectory);
SortItems(); if (!Load())
Save(); {
Scan(rct2Directory, TRIF_READ_ONLY);
Scan(userDirectory);
SortItems();
Save();
}
} }
bool Delete(const utf8 * path) override bool Delete(const utf8 * path) override
@ -193,6 +206,14 @@ public:
} }
private: private:
void Query(const utf8 * directory)
{
utf8 pattern[MAX_PATH];
String::Set(pattern, sizeof(pattern), directory);
Path::Append(pattern, sizeof(pattern), "*.td4;*.td6");
Path::QueryDirectory(&_directoryQueryResult, pattern);
}
void Scan(const utf8 * directory, uint32 flags = 0) void Scan(const utf8 * directory, uint32 flags = 0)
{ {
utf8 pattern[MAX_PATH]; utf8 pattern[MAX_PATH];
@ -240,6 +261,46 @@ private:
}); });
} }
bool Load()
{
utf8 path[MAX_PATH];
GetRepositoryPath(path, sizeof(path));
bool result = false;
try
{
auto fs = FileStream(path, FILE_MODE_OPEN);
// Read header, check if we need to re-scan
auto header = fs.ReadValue<TrackRepositoryHeader>();
if (header.MagicNumber == TRACK_REPOSITORY_MAGIC_NUMBER &&
header.Version == TRACK_REPOSITORY_VERSION &&
header.TotalFiles == _directoryQueryResult.TotalFiles &&
header.TotalFileSize == _directoryQueryResult.TotalFileSize &&
header.FileDateModifiedChecksum == _directoryQueryResult.FileDateModifiedChecksum &&
header.PathChecksum == _directoryQueryResult.PathChecksum)
{
// Directory is the same, just read the saved items
for (uint32 i = 0; i < header.NumItems; i++)
{
TrackRepositoryItem item;
item.Name = fs.ReadString();
item.Path = fs.ReadString();
item.RideType = fs.ReadValue<uint8>();
item.ObjectEntry = fs.ReadString();
item.Flags = fs.ReadValue<uint32>();
_items.push_back(item);
}
result = true;
}
}
catch (Exception ex)
{
Console::Error::WriteLine("Unable to write object repository index.");
}
return result;
}
void Save() const void Save() const
{ {
utf8 path[MAX_PATH]; utf8 path[MAX_PATH];
@ -253,6 +314,10 @@ private:
TrackRepositoryHeader header = { 0 }; TrackRepositoryHeader header = { 0 };
header.MagicNumber = TRACK_REPOSITORY_MAGIC_NUMBER; header.MagicNumber = TRACK_REPOSITORY_MAGIC_NUMBER;
header.Version = TRACK_REPOSITORY_VERSION; header.Version = TRACK_REPOSITORY_VERSION;
header.TotalFiles = _directoryQueryResult.TotalFiles;
header.TotalFileSize = _directoryQueryResult.TotalFileSize;
header.FileDateModifiedChecksum = _directoryQueryResult.FileDateModifiedChecksum;
header.PathChecksum = _directoryQueryResult.PathChecksum;
header.NumItems = (uint32)_items.size(); header.NumItems = (uint32)_items.size();
fs.WriteValue(header); fs.WriteValue(header);