]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/acquire.cc
acquire: Use priority queues and a 3 stage pipeline design
[apt.git] / apt-pkg / acquire.cc
index 29362fb407c96ba21d5bce7e1791d4a624ec5191..2ad6bc47f91c3a846ce658faeaab84acd37eda6c 100644 (file)
@@ -80,7 +80,7 @@ void pkgAcquire::Initialize()
    if (getuid() == 0 && SandboxUser.empty() == false && SandboxUser != "root") // if we aren't root, we can't chown, so don't try it
    {
       struct passwd const * const pw = getpwnam(SandboxUser.c_str());
-      struct group const * const gr = getgrnam("root");
+      struct group const * const gr = getgrnam(ROOT_GROUP);
       if (pw != NULL && gr != NULL)
       {
         std::string const AuthConf = _config->FindFile("Dir::Etc::netrc");
@@ -106,7 +106,7 @@ static bool SetupAPTPartialDirectory(std::string const &grand, std::string const
    if (getuid() == 0 && SandboxUser.empty() == false && SandboxUser != "root") // if we aren't root, we can't chown, so don't try it
    {
       struct passwd const * const pw = getpwnam(SandboxUser.c_str());
-      struct group const * const gr = getgrnam("root");
+      struct group const * const gr = getgrnam(ROOT_GROUP);
       if (pw != NULL && gr != NULL)
       {
          // chown the partial dir
@@ -269,6 +269,42 @@ void pkgAcquire::Remove(Worker *Work)
    it is constructed which creates a queue (based on the current queue
    mode) and puts the item in that queue. If the system is running then
    the queue might be started. */
+static bool CheckForBadItemAndFailIt(pkgAcquire::Item * const Item,
+      pkgAcquire::MethodConfig const * const Config, pkgAcquireStatus * const Log)
+{
+   auto SavedDesc = Item->GetItemDesc();
+   if (Item->IsRedirectionLoop(SavedDesc.URI))
+   {
+      std::string const Message = "400 URI Failure"
+        "\nURI: " + SavedDesc.URI +
+        "\nFilename: " + Item->DestFile +
+        "\nFailReason: RedirectionLoop";
+
+      Item->Status = pkgAcquire::Item::StatError;
+      Item->Failed(Message, Config);
+      if (Log != nullptr)
+        Log->Fail(SavedDesc);
+      return true;
+   }
+
+   HashStringList const hsl = Item->GetExpectedHashes();
+   if (hsl.usable() == false && Item->HashesRequired() &&
+        _config->Exists("Acquire::ForceHash") == false)
+   {
+      std::string const Message = "400 URI Failure"
+        "\nURI: " + SavedDesc.URI +
+        "\nFilename: " + Item->DestFile +
+        "\nFailReason: WeakHashSums";
+
+      auto SavedDesc = Item->GetItemDesc();
+      Item->Status = pkgAcquire::Item::StatAuthError;
+      Item->Failed(Message, Config);
+      if (Log != nullptr)
+        Log->Fail(SavedDesc);
+      return true;
+   }
+   return false;
+}
 void pkgAcquire::Enqueue(ItemDesc &Item)
 {
    // Determine which queue to put the item in
@@ -277,6 +313,13 @@ void pkgAcquire::Enqueue(ItemDesc &Item)
    if (Name.empty() == true)
       return;
 
+   /* the check for running avoids that we produce errors
+      in logging before we actually have started, which would
+      be easier to implement but would confuse users/implementations
+      so we check the items skipped here in #Startup */
+   if (Running && CheckForBadItemAndFailIt(Item.Owner, Config, Log))
+      return;
+
    // Find the queue structure
    Queue *I = Queues;
    for (; I != 0 && I->Name != Name; I = I->Next);
@@ -851,9 +894,10 @@ pkgAcquire::Queue::~Queue()
 /* */
 bool pkgAcquire::Queue::Enqueue(ItemDesc &Item)
 {
+   QItem **OptimalI = &Items;
    QItem **I = &Items;
    // move to the end of the queue and check for duplicates here
-   for (; *I != 0; I = &(*I)->Next)
+   for (; *I != 0; ) {
       if (Item.URI == (*I)->URI)
       {
         if (_config->FindB("Debug::pkgAcquire::Worker",false) == true)
@@ -862,12 +906,22 @@ bool pkgAcquire::Queue::Enqueue(ItemDesc &Item)
         Item.Owner->Status = (*I)->Owner->Status;
         return false;
       }
+      // Determine the optimal position to insert: before anything with a
+      // higher priority.
+      int priority = (*I)->GetPriority();
+
+      I = &(*I)->Next;
+      if (priority >= Item.Owner->Priority()) {
+        OptimalI = I;
+      }
+   }
+
 
    // Create a new item
    QItem *Itm = new QItem;
    *Itm = Item;
-   Itm->Next = 0;
-   *I = Itm;
+   Itm->Next = *OptimalI;
+   *OptimalI = Itm;
    
    Item.Owner->QueueCounter++;   
    if (Items->Next == 0)
@@ -912,10 +966,20 @@ bool pkgAcquire::Queue::Startup()
    if (Workers == 0)
    {
       URI U(Name);
-      pkgAcquire::MethodConfig *Cnf = Owner->GetConfig(U.Access);
-      if (Cnf == 0)
+      pkgAcquire::MethodConfig * const Cnf = Owner->GetConfig(U.Access);
+      if (unlikely(Cnf == nullptr))
         return false;
-      
+
+      // now-running twin of the pkgAcquire::Enqueue call
+      for (QItem *I = Items; I != 0; )
+      {
+        auto const INext = I->Next;
+        for (auto &&O: I->Owners)
+           CheckForBadItemAndFailIt(O, Cnf, Owner->Log);
+        // if an item failed, it will be auto-dequeued invalidation our I here
+        I = INext;
+      }
+
       Workers = new Worker(this,Cnf,Owner->Log);
       Owner->Add(Workers);
       if (Workers->Start() == false)
@@ -1007,16 +1071,24 @@ bool pkgAcquire::Queue::Cycle()
 
    // Look for a queable item
    QItem *I = Items;
+   int ActivePriority = 0;
    while (PipeDepth < (signed)MaxPipeDepth)
    {
-      for (; I != 0; I = I->Next)
+      for (; I != 0; I = I->Next) {
+        if (I->Owner->Status == pkgAcquire::Item::StatFetching)
+           ActivePriority = std::max(ActivePriority, I->GetPriority());
         if (I->Owner->Status == pkgAcquire::Item::StatIdle)
            break;
+      }
 
       // Nothing to do, queue is idle.
       if (I == 0)
         return true;
 
+      // This item has a lower priority than stuff in the pipeline, pretend
+      // the queue is idle
+      if (I->GetPriority() < ActivePriority)
+        return true;
       I->Worker = Workers;
       for (auto const &O: I->Owners)
         O->Status = pkgAcquire::Item::StatFetching;
@@ -1082,6 +1154,15 @@ APT_PURE unsigned long long pkgAcquire::Queue::QItem::GetMaximumSize() const     /*{
    return Maximum;
 }
                                                                        /*}}}*/
+APT_PURE int pkgAcquire::Queue::QItem::GetPriority() const     /*{{{*/
+{
+   int Priority = 0;
+   for (auto const &O: Owners)
+      Priority = std::max(Priority, O->Priority());
+
+   return Priority;
+}
+                                                                       /*}}}*/
 void pkgAcquire::Queue::QItem::SyncDestinationFiles() const            /*{{{*/
 {
    /* ensure that the first owner has the best partial file of all and
@@ -1258,8 +1339,11 @@ bool pkgAcquireStatus::Pulse(pkgAcquire *Owner)
         snprintf(msg,sizeof(msg), _("Retrieving file %li of %li"), i, TotalItems);
 
       // build the status str
-      std::string dlstatus;
-      strprintf(dlstatus, "dlstatus:%ld:%.4f:%s\n", i, Percent, msg);
+      std::ostringstream str;
+      str.imbue(std::locale::classic());
+      str.precision(4);
+      str << "dlstatus" << ':' << std::fixed << i << ':' << Percent << ':' << msg << '\n';
+      auto const dlstatus = str.str();
       FileFd::Write(fd, dlstatus.data(), dlstatus.size());
    }