Package Kit: Improvements to partial download handling.
* Move IsDownloadComplete call into DownloadFileRequest; this way we will always revalidate checksums even if the file is fully downloaded instead of skipping that. * Treat ERANGE as a "bad data" error in PackageManager (it usually means we have a size mismatch between the local and the server's file) * If we fail checksum validation or get ERANGE, and we reused a download, immediately try again without reusing the download. This fixes most problems that previously required you to delete old transaction directories. Change-Id: Ia3079655691b871e0b206e366b59fca0f832c63d Reviewed-on: https://review.haiku-os.org/c/haiku/+/4730 Reviewed-by: waddlesplash <waddlesplash@gmail.com>
This commit is contained in:
parent
001e157a7b
commit
2be10edfb9
@ -12,6 +12,7 @@
|
|||||||
#include <package/ValidateChecksumJob.h>
|
#include <package/ValidateChecksumJob.h>
|
||||||
|
|
||||||
#include "FetchFileJob.h"
|
#include "FetchFileJob.h"
|
||||||
|
#include "FetchUtils.h"
|
||||||
|
|
||||||
|
|
||||||
namespace BPackageKit {
|
namespace BPackageKit {
|
||||||
@ -49,6 +50,7 @@ DownloadFileRequest::CreateInitialJobs()
|
|||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return B_NO_INIT;
|
return B_NO_INIT;
|
||||||
|
|
||||||
|
if (!FetchUtils::IsDownloadCompleted(BNode(&fTargetEntry))) {
|
||||||
// create the download job
|
// create the download job
|
||||||
FetchFileJob* fetchJob = new (std::nothrow) FetchFileJob(fContext,
|
FetchFileJob* fetchJob = new (std::nothrow) FetchFileJob(fContext,
|
||||||
BString("Downloading ") << fFileURL, fFileURL, fTargetEntry);
|
BString("Downloading ") << fFileURL, fFileURL, fTargetEntry);
|
||||||
@ -59,6 +61,7 @@ DownloadFileRequest::CreateInitialJobs()
|
|||||||
delete fetchJob;
|
delete fetchJob;
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// create the checksum validation job
|
// create the checksum validation job
|
||||||
if (fChecksum.IsEmpty())
|
if (fChecksum.IsEmpty())
|
||||||
|
@ -34,7 +34,7 @@ FetchUtils::IsDownloadCompleted(const char* path)
|
|||||||
|
|
||||||
|
|
||||||
/*static*/ bool
|
/*static*/ bool
|
||||||
FetchUtils::IsDownloadCompleted(BNode& node)
|
FetchUtils::IsDownloadCompleted(const BNode& node)
|
||||||
{
|
{
|
||||||
bool isComplete;
|
bool isComplete;
|
||||||
status_t status = _GetAttribute(node, DL_COMPLETE_ATTR,
|
status_t status = _GetAttribute(node, DL_COMPLETE_ATTR,
|
||||||
@ -84,7 +84,7 @@ FetchUtils::_SetAttribute(BNode& node, const char* attrName,
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
FetchUtils::_GetAttribute(BNode& node, const char* attrName,
|
FetchUtils::_GetAttribute(const BNode& node, const char* attrName,
|
||||||
type_code type, void* data, size_t size)
|
type_code type, void* data, size_t size)
|
||||||
{
|
{
|
||||||
if (node.InitCheck() != B_OK)
|
if (node.InitCheck() != B_OK)
|
||||||
|
@ -17,7 +17,7 @@ namespace BPrivate {
|
|||||||
class FetchUtils {
|
class FetchUtils {
|
||||||
public:
|
public:
|
||||||
static bool IsDownloadCompleted(const char* path);
|
static bool IsDownloadCompleted(const char* path);
|
||||||
static bool IsDownloadCompleted(BNode& node);
|
static bool IsDownloadCompleted(const BNode& node);
|
||||||
|
|
||||||
static status_t MarkDownloadComplete(const char* path);
|
static status_t MarkDownloadComplete(const char* path);
|
||||||
static status_t MarkDownloadComplete(BNode& node);
|
static status_t MarkDownloadComplete(BNode& node);
|
||||||
@ -29,7 +29,7 @@ private:
|
|||||||
const char* attrName,
|
const char* attrName,
|
||||||
type_code type, const void* data,
|
type_code type, const void* data,
|
||||||
size_t size);
|
size_t size);
|
||||||
static status_t _GetAttribute(BNode& node,
|
static status_t _GetAttribute(const BNode& node,
|
||||||
const char* attrName,
|
const char* attrName,
|
||||||
type_code type, void* data,
|
type_code type, void* data,
|
||||||
size_t size);
|
size_t size);
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
|
|
||||||
#include "FetchFileJob.h"
|
#include "FetchFileJob.h"
|
||||||
#include "FetchUtils.h"
|
#include "FetchUtils.h"
|
||||||
|
using BPackageKit::BPrivate::FetchUtils;
|
||||||
#include "PackageManagerUtils.h"
|
#include "PackageManagerUtils.h"
|
||||||
|
|
||||||
#undef B_TRANSLATION_CONTEXT
|
#undef B_TRANSLATION_CONTEXT
|
||||||
@ -41,7 +42,6 @@
|
|||||||
|
|
||||||
|
|
||||||
using BPackageKit::BPrivate::FetchFileJob;
|
using BPackageKit::BPrivate::FetchFileJob;
|
||||||
using BPackageKit::BPrivate::FetchUtils;
|
|
||||||
using BPackageKit::BPrivate::ValidateChecksumJob;
|
using BPackageKit::BPrivate::ValidateChecksumJob;
|
||||||
|
|
||||||
|
|
||||||
@ -564,7 +564,7 @@ BPackageManager::_PreparePackageChanges(
|
|||||||
RemoteRepository* remoteRepository
|
RemoteRepository* remoteRepository
|
||||||
= dynamic_cast<RemoteRepository*>(package->Repository());
|
= dynamic_cast<RemoteRepository*>(package->Repository());
|
||||||
if (remoteRepository != NULL) {
|
if (remoteRepository != NULL) {
|
||||||
bool alreadyDownloaded = false;
|
bool reusingDownload = false;
|
||||||
|
|
||||||
// Check for matching files in already existing transaction
|
// Check for matching files in already existing transaction
|
||||||
// directories
|
// directories
|
||||||
@ -593,34 +593,43 @@ BPackageManager::_PreparePackageChanges(
|
|||||||
path.Append(fileName);
|
path.Append(fileName);
|
||||||
if (bestFile != NULL && BCopyEngine().CopyEntry(bestFile,
|
if (bestFile != NULL && BCopyEngine().CopyEntry(bestFile,
|
||||||
path.Path()) == B_OK) {
|
path.Path()) == B_OK) {
|
||||||
alreadyDownloaded = FetchUtils::IsDownloadCompleted(
|
reusingDownload = true;
|
||||||
path.Path());
|
|
||||||
printf("Re-using download '%s' from previous "
|
printf("Re-using download '%s' from previous "
|
||||||
"transaction%s\n", bestFile,
|
"transaction%s\n", bestFile,
|
||||||
alreadyDownloaded ? "" : " (partial)");
|
FetchUtils::IsDownloadCompleted(
|
||||||
|
path.Path()) ? "" : " (partial)");
|
||||||
}
|
}
|
||||||
globfree(&globbuf);
|
globfree(&globbuf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!alreadyDownloaded) {
|
|
||||||
// download the package (this will resume the download if the
|
// download the package (this will resume the download if the
|
||||||
// file already exists)
|
// file already exists)
|
||||||
BString url = remoteRepository->Config().PackagesURL();
|
BString url = remoteRepository->Config().PackagesURL();
|
||||||
url << '/' << fileName;
|
url << '/' << fileName;
|
||||||
|
|
||||||
status_t error = DownloadPackage(url, entry,
|
status_t error;
|
||||||
|
retryDownload:
|
||||||
|
error = DownloadPackage(url, entry,
|
||||||
package->Info().Checksum());
|
package->Info().Checksum());
|
||||||
if (error != B_OK) {
|
if (error != B_OK) {
|
||||||
if (error == B_BAD_DATA) {
|
if (error == B_BAD_DATA || error == ERANGE) {
|
||||||
// B_BAD_DATA is returned when there is a checksum
|
// B_BAD_DATA is returned when there is a checksum
|
||||||
// mismatch. Make sure this download is not re-used.
|
// mismatch. Make sure this download is not re-used.
|
||||||
entry.Remove();
|
entry.Remove();
|
||||||
|
|
||||||
|
if (reusingDownload) {
|
||||||
|
// Maybe the download we reused had some problem.
|
||||||
|
// Try again, this time without reusing the download.
|
||||||
|
printf("\nPrevious download '%s' was invalid. Redownloading.\n",
|
||||||
|
path.Path());
|
||||||
|
reusingDownload = false;
|
||||||
|
goto retryDownload;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
DIE(error, "Failed to download package %s",
|
DIE(error, "Failed to download package %s",
|
||||||
package->Info().Name().String());
|
package->Info().Name().String());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else if (package->Repository() != &installationRepository) {
|
} else if (package->Repository() != &installationRepository) {
|
||||||
// clone the existing package
|
// clone the existing package
|
||||||
LocalRepository* localRepository
|
LocalRepository* localRepository
|
||||||
|
Loading…
Reference in New Issue
Block a user