TerraSync: stronger fix for handling 0-byte files
Change logic so we create an empty file for such cases, i.e exactly matching the repository. This simplifies logic in downstream code, compared with not creating a local file. Add a test-case to cover this Modify TerraSync to detect a failure of Airports_archive downloading, and fall back to file-by-file updating.
This commit is contained in:
parent
57a4dc53f2
commit
191d546b54
@ -979,17 +979,14 @@ HTTPRepository::failure() const
|
|||||||
{
|
{
|
||||||
pathInRepo = _directory->absolutePath();
|
pathInRepo = _directory->absolutePath();
|
||||||
pathInRepo.append(fileName);
|
pathInRepo.append(fileName);
|
||||||
|
|
||||||
sha1_init(&hashContext);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void gotBodyData(const char *s, int n) override {
|
void gotBodyData(const char* s, int n) override
|
||||||
|
{
|
||||||
if (!file.get()) {
|
if (!file.get()) {
|
||||||
file.reset(new SGBinaryFile(pathInRepo));
|
const bool ok = createOutputFile();
|
||||||
if (!file->open(SG_IO_OUT)) {
|
if (!ok) {
|
||||||
SG_LOG(SG_TERRASYNC, SG_WARN,
|
|
||||||
"unable to create file " << pathInRepo);
|
|
||||||
_directory->repository()->http->cancelRequest(
|
_directory->repository()->http->cancelRequest(
|
||||||
this, "Unable to create output file:" + pathInRepo.utf8Str());
|
this, "Unable to create output file:" + pathInRepo.utf8Str());
|
||||||
}
|
}
|
||||||
@ -999,12 +996,34 @@ HTTPRepository::failure() const
|
|||||||
file->write(s, n);
|
file->write(s, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onDone() override {
|
bool createOutputFile()
|
||||||
|
{
|
||||||
|
file.reset(new SGBinaryFile(pathInRepo));
|
||||||
|
if (!file->open(SG_IO_OUT)) {
|
||||||
|
SG_LOG(SG_TERRASYNC, SG_WARN,
|
||||||
|
"unable to create file " << pathInRepo);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sha1_init(&hashContext);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void onDone() override
|
||||||
|
{
|
||||||
|
const bool is200Response = (responseCode() == 200);
|
||||||
|
if (!file && is200Response) {
|
||||||
|
// if the server defines a zero-byte file, we will never call
|
||||||
|
// gotBodyData, so create the file here
|
||||||
|
// this ensures all the logic below works as expected
|
||||||
|
createOutputFile();
|
||||||
|
}
|
||||||
|
|
||||||
if (file) {
|
if (file) {
|
||||||
file->close();
|
file->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (responseCode() == 200) {
|
if (is200Response) {
|
||||||
std::string hash =
|
std::string hash =
|
||||||
strutils::encodeHex(sha1_result(&hashContext), HASH_LENGTH);
|
strutils::encodeHex(sha1_result(&hashContext), HASH_LENGTH);
|
||||||
_directory->didUpdateFile(fileName, hash, contentSize());
|
_directory->didUpdateFile(fileName, hash, contentSize());
|
||||||
|
@ -31,6 +31,10 @@ using TestApi = simgear::HTTP::TestApi;
|
|||||||
|
|
||||||
std::string dataForFile(const std::string& parentName, const std::string& name, int revision)
|
std::string dataForFile(const std::string& parentName, const std::string& name, int revision)
|
||||||
{
|
{
|
||||||
|
if (name == "zeroByteFile") {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
std::ostringstream os;
|
std::ostringstream os;
|
||||||
// random content but which definitely depends on our tree location
|
// random content but which definitely depends on our tree location
|
||||||
// and revision.
|
// and revision.
|
||||||
@ -446,6 +450,7 @@ void testBasicClone(HTTP::Client* cl)
|
|||||||
verifyFileState(p, "fileA");
|
verifyFileState(p, "fileA");
|
||||||
verifyFileState(p, "dirA/subdirA/fileAAA");
|
verifyFileState(p, "dirA/subdirA/fileAAA");
|
||||||
verifyFileState(p, "dirC/subdirA/subsubA/fileCAAA");
|
verifyFileState(p, "dirC/subdirA/subsubA/fileCAAA");
|
||||||
|
verifyFileState(p, "dirA/subdirA/zeroByteFile");
|
||||||
|
|
||||||
global_repo->findEntry("fileA")->revision++;
|
global_repo->findEntry("fileA")->revision++;
|
||||||
global_repo->findEntry("dirB/subdirA/fileBAA")->revision++;
|
global_repo->findEntry("dirB/subdirA/fileBAA")->revision++;
|
||||||
@ -911,6 +916,8 @@ int main(int argc, char* argv[])
|
|||||||
global_repo->defineFile("dirA/fileAC");
|
global_repo->defineFile("dirA/fileAC");
|
||||||
global_repo->defineFile("dirA/subdirA/fileAAA");
|
global_repo->defineFile("dirA/subdirA/fileAAA");
|
||||||
global_repo->defineFile("dirA/subdirA/fileAAB");
|
global_repo->defineFile("dirA/subdirA/fileAAB");
|
||||||
|
global_repo->defineFile("dirA/subdirA/zeroByteFile");
|
||||||
|
|
||||||
global_repo->defineFile("dirB/subdirA/fileBAA");
|
global_repo->defineFile("dirB/subdirA/fileBAA");
|
||||||
global_repo->defineFile("dirB/subdirA/fileBAB");
|
global_repo->defineFile("dirB/subdirA/fileBAB");
|
||||||
global_repo->defineFile("dirB/subdirA/fileBAC");
|
global_repo->defineFile("dirB/subdirA/fileBAC");
|
||||||
|
@ -571,6 +571,15 @@ void SGTerraSync::WorkerThread::updateSyncSlot(SyncSlot &slot)
|
|||||||
notFound(slot.currentItem);
|
notFound(slot.currentItem);
|
||||||
} else if (res != HTTPRepository::REPO_NO_ERROR) {
|
} else if (res != HTTPRepository::REPO_NO_ERROR) {
|
||||||
fail(slot.currentItem);
|
fail(slot.currentItem);
|
||||||
|
|
||||||
|
// in case the Airports_archive download fails, create the
|
||||||
|
// directory, so that next sync, we do a manual sync
|
||||||
|
if ((slot.currentItem._type == SyncItem::AirportData) && slot.isNewDirectory) {
|
||||||
|
SG_LOG(SG_TERRASYNC, SG_ALERT, "Failed to download Airports_archive, will download discrete files next time");
|
||||||
|
simgear::Dir d(_local_dir + "/Airports");
|
||||||
|
d.create(0755);
|
||||||
|
_completedTiles.erase(slot.currentItem._dir);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
updated(slot.currentItem, slot.isNewDirectory);
|
updated(slot.currentItem, slot.isNewDirectory);
|
||||||
SG_LOG(SG_TERRASYNC, SG_DEBUG, "sync of " << slot.repository->baseUrl() << " finished ("
|
SG_LOG(SG_TERRASYNC, SG_DEBUG, "sync of " << slot.repository->baseUrl() << " finished ("
|
||||||
|
Loading…
Reference in New Issue
Block a user