summaryrefslogtreecommitdiff
path: root/apt-pkg/acquire-worker.cc
diff options
context:
space:
mode:
authorDavid Kalnischkies <david@kalnischkies.de>2015-06-15 13:16:43 +0200
committerDavid Kalnischkies <david@kalnischkies.de>2015-06-15 23:34:05 +0200
commit08ea7806458de0995414eaae852e0a5985875642 (patch)
tree97ac4a9db80bff757d94666df4db429fbf39cbbe /apt-pkg/acquire-worker.cc
parent9f697f69cf1adaced476598cfe08ab03c76c5d18 (diff)
deal better with acquiring the same URI multiple times
This is an unlikely event for indexes and co, but it can happen quiet easily e.g. for changelogs where you want to get the changelogs for multiple binary package(version)s which happen to all be built from a single source. The interesting part is that the Acquire system actually detected this already and set the item requesting the URI again to StatDone - expect that this is hardly sufficient: an Item must be Complete=true as well to be considered truely done and that is only the tip of the ::Done handling iceberg. So instead of this StatDone hack we allow QItems to be owned by multiple items and notify all owners about everything now, so that for the point of each item they got it downloaded just for them.
Diffstat (limited to 'apt-pkg/acquire-worker.cc')
-rw-r--r--apt-pkg/acquire-worker.cc280
1 files changed, 169 insertions, 111 deletions
diff --git a/apt-pkg/acquire-worker.cc b/apt-pkg/acquire-worker.cc
index 099a1f87d..d6318a21b 100644
--- a/apt-pkg/acquire-worker.cc
+++ b/apt-pkg/acquire-worker.cc
@@ -258,18 +258,27 @@ bool pkgAcquire::Worker::RunMessages()
ItemDone();
- pkgAcquire::Item *Owner = Itm->Owner;
- pkgAcquire::ItemDesc Desc = *Itm;
-
// Change the status so that it can be dequeued
- Owner->Status = pkgAcquire::Item::StatIdle;
+ for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
+ {
+ pkgAcquire::Item *Owner = *O;
+ Owner->Status = pkgAcquire::Item::StatIdle;
+ }
// Mark the item as done (taking care of all queues)
// and then put it in the main queue again
+ std::vector<Item*> const ItmOwners = Itm->Owners;
OwnerQ->ItemDone(Itm);
- OwnerQ->Owner->Enqueue(Desc);
+ Itm = NULL;
+ for (pkgAcquire::Queue::QItem::owner_iterator O = ItmOwners.begin(); O != ItmOwners.end(); ++O)
+ {
+ pkgAcquire::Item *Owner = *O;
+ pkgAcquire::ItemDesc desc = Owner->GetItemDesc();
+ desc.URI = NewURI;
+ OwnerQ->Owner->Enqueue(desc);
- if (Log != 0)
- Log->Done(Desc);
+ if (Log != 0)
+ Log->Done(Owner->GetItemDesc());
+ }
break;
}
@@ -286,14 +295,18 @@ bool pkgAcquire::Worker::RunMessages()
CurrentSize = 0;
TotalSize = strtoull(LookupTag(Message,"Size","0").c_str(), NULL, 10);
ResumePoint = strtoull(LookupTag(Message,"Resume-Point","0").c_str(), NULL, 10);
- Itm->Owner->Start(Message, TotalSize);
-
- // Display update before completion
- if (Log != 0 && Log->MorePulses == true)
- Log->Pulse(Itm->Owner->GetOwner());
+ for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
+ {
+ (*O)->Start(Message, TotalSize);
- if (Log != 0)
- Log->Fetch(*Itm);
+ // Display update before completion
+ if (Log != 0)
+ {
+ if (Log->MorePulses == true)
+ Log->Pulse((*O)->GetOwner());
+ Log->Fetch((*O)->GetItemDesc());
+ }
+ }
break;
}
@@ -307,105 +320,110 @@ bool pkgAcquire::Worker::RunMessages()
break;
}
- pkgAcquire::Item *Owner = Itm->Owner;
- pkgAcquire::ItemDesc Desc = *Itm;
-
- if (RealFileExists(Owner->DestFile))
- ChangeOwnerAndPermissionOfFile("201::URIDone", Owner->DestFile.c_str(), "root", "root", 0644);
+ PrepareFiles("201::URIDone", Itm);
// Display update before completion
if (Log != 0 && Log->MorePulses == true)
- Log->Pulse(Owner->GetOwner());
+ for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
+ Log->Pulse((*O)->GetOwner());
- OwnerQ->ItemDone(Itm);
-
- HashStringList const ExpectedHashes = Owner->GetExpectedHashes();
- // see if we got hashes to verify
+ std::string const filename = LookupTag(Message, "Filename", Itm->Owner->DestFile.c_str());
HashStringList ReceivedHashes;
- for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
{
- std::string const tagname = std::string(*type) + "-Hash";
- std::string const hashsum = LookupTag(Message, tagname.c_str());
- if (hashsum.empty() == false)
- ReceivedHashes.push_back(HashString(*type, hashsum));
- }
- // not all methods always sent Hashes our way
- if (ExpectedHashes.usable() == true && ReceivedHashes.usable() == false)
- {
- std::string const filename = LookupTag(Message, "Filename", Owner->DestFile.c_str());
- if (filename.empty() == false && RealFileExists(filename))
+ // see if we got hashes to verify
+ for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
{
- Hashes calc(ExpectedHashes);
- FileFd file(filename, FileFd::ReadOnly, FileFd::None);
- calc.AddFD(file);
- ReceivedHashes = calc.GetHashStringList();
+ std::string const tagname = std::string(*type) + "-Hash";
+ std::string const hashsum = LookupTag(Message, tagname.c_str());
+ if (hashsum.empty() == false)
+ ReceivedHashes.push_back(HashString(*type, hashsum));
+ }
+ // not all methods always sent Hashes our way
+ if (ReceivedHashes.usable() == false)
+ {
+ HashStringList const ExpectedHashes = Itm->GetExpectedHashes();
+ if (ExpectedHashes.usable() == true && RealFileExists(filename))
+ {
+ Hashes calc(ExpectedHashes);
+ FileFd file(filename, FileFd::ReadOnly, FileFd::None);
+ calc.AddFD(file);
+ ReceivedHashes = calc.GetHashStringList();
+ }
}
}
- if(_config->FindB("Debug::pkgAcquire::Auth", false) == true)
- {
- std::clog << "201 URI Done: " << Owner->DescURI() << endl
- << "ReceivedHash:" << endl;
- for (HashStringList::const_iterator hs = ReceivedHashes.begin(); hs != ReceivedHashes.end(); ++hs)
- std::clog << "\t- " << hs->toStr() << std::endl;
- std::clog << "ExpectedHash:" << endl;
- for (HashStringList::const_iterator hs = ExpectedHashes.begin(); hs != ExpectedHashes.end(); ++hs)
- std::clog << "\t- " << hs->toStr() << std::endl;
- std::clog << endl;
- }
+ // only local files can refer other filenames and counting them as fetched would be unfair
+ if (Log != NULL && filename != Itm->Owner->DestFile)
+ Log->Fetched(ReceivedHashes.FileSize(),atoi(LookupTag(Message,"Resume-Point","0").c_str()));
+
+ std::vector<Item*> const ItmOwners = Itm->Owners;
+ OwnerQ->ItemDone(Itm);
+ Itm = NULL;
- // decide if what we got is what we expected
- bool consideredOkay = false;
bool const isIMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false) ||
StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false);
- if (ExpectedHashes.usable())
+
+ for (pkgAcquire::Queue::QItem::owner_iterator O = ItmOwners.begin(); O != ItmOwners.end(); ++O)
{
- if (ReceivedHashes.usable() == false)
+ pkgAcquire::Item * const Owner = *O;
+ HashStringList const ExpectedHashes = Owner->GetExpectedHashes();
+ if(_config->FindB("Debug::pkgAcquire::Auth", false) == true)
{
- /* IMS-Hits can't be checked here as we will have uncompressed file,
- but the hashes for the compressed file. What we have was good through
- so all we have to ensure later is that we are not stalled. */
- consideredOkay = isIMSHit;
+ std::clog << "201 URI Done: " << Owner->DescURI() << endl
+ << "ReceivedHash:" << endl;
+ for (HashStringList::const_iterator hs = ReceivedHashes.begin(); hs != ReceivedHashes.end(); ++hs)
+ std::clog << "\t- " << hs->toStr() << std::endl;
+ std::clog << "ExpectedHash:" << endl;
+ for (HashStringList::const_iterator hs = ExpectedHashes.begin(); hs != ExpectedHashes.end(); ++hs)
+ std::clog << "\t- " << hs->toStr() << std::endl;
+ std::clog << endl;
}
- else if (ReceivedHashes == ExpectedHashes)
- consideredOkay = true;
- else
- consideredOkay = false;
- }
- else if (Owner->HashesRequired() == true)
- consideredOkay = false;
- else
- consideredOkay = true;
+ // decide if what we got is what we expected
+ bool consideredOkay = false;
+ if (ExpectedHashes.usable())
+ {
+ if (ReceivedHashes.usable() == false)
+ {
+ /* IMS-Hits can't be checked here as we will have uncompressed file,
+ but the hashes for the compressed file. What we have was good through
+ so all we have to ensure later is that we are not stalled. */
+ consideredOkay = isIMSHit;
+ }
+ else if (ReceivedHashes == ExpectedHashes)
+ consideredOkay = true;
+ else
+ consideredOkay = false;
- if (consideredOkay == true)
- {
- Owner->Done(Message, ReceivedHashes, Config);
- ItemDone();
+ }
+ else if (Owner->HashesRequired() == true)
+ consideredOkay = false;
+ else
+ consideredOkay = true;
- // Log that we are done
- if (Log != 0)
+ if (consideredOkay == true)
{
- if (isIMSHit)
+ Owner->Done(Message, ReceivedHashes, Config);
+
+ // Log that we are done
+ if (Log != 0)
{
- /* Hide 'hits' for local only sources - we also manage to
- hide gets */
- if (Config->LocalOnly == false)
- Log->IMSHit(Desc);
+ if (isIMSHit)
+ Log->IMSHit(Owner->GetItemDesc());
+ else
+ Log->Done(Owner->GetItemDesc());
}
- else
- Log->Done(Desc);
}
- }
- else
- {
- Owner->Status = pkgAcquire::Item::StatAuthError;
- Owner->Failed(Message,Config);
- ItemDone();
+ else
+ {
+ Owner->Status = pkgAcquire::Item::StatAuthError;
+ Owner->Failed(Message,Config);
- if (Log != 0)
- Log->Fail(Desc);
+ if (Log != 0)
+ Log->Fail(Owner->GetItemDesc());
+ }
}
+ ItemDone();
break;
}
@@ -419,30 +437,32 @@ bool pkgAcquire::Worker::RunMessages()
break;
}
+ PrepareFiles("400::URIFailure", Itm);
+
// Display update before completion
if (Log != 0 && Log->MorePulses == true)
- Log->Pulse(Itm->Owner->GetOwner());
-
- pkgAcquire::Item *Owner = Itm->Owner;
- pkgAcquire::ItemDesc Desc = *Itm;
-
- if (RealFileExists(Owner->DestFile))
- ChangeOwnerAndPermissionOfFile("400::URIFailure", Owner->DestFile.c_str(), "root", "root", 0644);
+ for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
+ Log->Pulse((*O)->GetOwner());
+ std::vector<Item*> const ItmOwners = Itm->Owners;
OwnerQ->ItemDone(Itm);
+ Itm = NULL;
- // set some status
- if(LookupTag(Message,"FailReason") == "Timeout" ||
- LookupTag(Message,"FailReason") == "TmpResolveFailure" ||
- LookupTag(Message,"FailReason") == "ResolveFailure" ||
- LookupTag(Message,"FailReason") == "ConnectionRefused")
- Owner->Status = pkgAcquire::Item::StatTransientNetworkError;
+ for (pkgAcquire::Queue::QItem::owner_iterator O = ItmOwners.begin(); O != ItmOwners.end(); ++O)
+ {
+ // set some status
+ if(LookupTag(Message,"FailReason") == "Timeout" ||
+ LookupTag(Message,"FailReason") == "TmpResolveFailure" ||
+ LookupTag(Message,"FailReason") == "ResolveFailure" ||
+ LookupTag(Message,"FailReason") == "ConnectionRefused")
+ (*O)->Status = pkgAcquire::Item::StatTransientNetworkError;
- Owner->Failed(Message,Config);
- ItemDone();
+ (*O)->Failed(Message,Config);
- if (Log != 0)
- Log->Fail(Desc);
+ if (Log != 0)
+ Log->Fail((*O)->GetItemDesc());
+ }
+ ItemDone();
break;
}
@@ -578,16 +598,24 @@ bool pkgAcquire::Worker::QueueItem(pkgAcquire::Queue::QItem *Item)
Message.reserve(300);
Message += "URI: " + Item->URI;
Message += "\nFilename: " + Item->Owner->DestFile;
- HashStringList const hsl = Item->Owner->GetExpectedHashes();
+
+ HashStringList const hsl = Item->GetExpectedHashes();
for (HashStringList::const_iterator hs = hsl.begin(); hs != hsl.end(); ++hs)
Message += "\nExpected-" + hs->HashType() + ": " + hs->HashValue();
- if(Item->Owner->FileSize > 0)
+
+ if (hsl.FileSize() == 0)
{
- string MaximumSize;
- strprintf(MaximumSize, "%llu", Item->Owner->FileSize);
- Message += "\nMaximum-Size: " + MaximumSize;
+ unsigned long long FileSize = Item->GetMaximumSize();
+ if(FileSize > 0)
+ {
+ string MaximumSize;
+ strprintf(MaximumSize, "%llu", FileSize);
+ Message += "\nMaximum-Size: " + MaximumSize;
+ }
}
- Message += Item->Owner->Custom600Headers();
+
+ Item->SyncDestinationFiles();
+ Message += Item->Custom600Headers();
Message += "\n\n";
if (RealFileExists(Item->Owner->DestFile))
@@ -686,3 +714,33 @@ void pkgAcquire::Worker::ItemDone()
Status = string();
}
/*}}}*/
+void pkgAcquire::Worker::PrepareFiles(char const * const caller, pkgAcquire::Queue::QItem const * const Itm)/*{{{*/
+{
+ if (RealFileExists(Itm->Owner->DestFile))
+ {
+ ChangeOwnerAndPermissionOfFile(caller, Itm->Owner->DestFile.c_str(), "root", "root", 0644);
+ std::string const filename = Itm->Owner->DestFile;
+ for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
+ {
+ pkgAcquire::Item const * const Owner = *O;
+ if (Owner->DestFile == filename)
+ continue;
+ unlink(Owner->DestFile.c_str());
+ if (link(filename.c_str(), Owner->DestFile.c_str()) != 0)
+ {
+ // diferent mounts can't happen for us as we download to lists/ by default,
+ // but if the system is reused by others the locations can potentially be on
+ // different disks, so use symlink as poor-men replacement.
+ // FIXME: Real copying as last fallback, but that is costly, so offload to a method preferable
+ if (symlink(filename.c_str(), Owner->DestFile.c_str()) != 0)
+ _error->Error("Can't create (sym)link of file %s to %s", filename.c_str(), Owner->DestFile.c_str());
+ }
+ }
+ }
+ else
+ {
+ for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
+ unlink((*O)->DestFile.c_str());
+ }
+}
+ /*}}}*/