- Allow computation of disk usage per solvable.
[platform/upstream/libzypp.git] / zypp / DiskUsageCounter.cc
index ab8c200..4b2afa6 100644 (file)
@@ -17,158 +17,125 @@ extern "C"
 #include <iostream>
 #include <fstream>
 
-#include "zypp/base/Logger.h"
+#include "zypp/base/Easy.h"
+#include "zypp/base/LogTools.h"
 #include "zypp/base/String.h"
 
 #include "zypp/DiskUsageCounter.h"
-#include "zypp/Package.h"
+#include "zypp/sat/Pool.h"
+#include "zypp/sat/detail/PoolImpl.h"
 
+using std::endl;
 
 ///////////////////////////////////////////////////////////////////
 namespace zypp
 { /////////////////////////////////////////////////////////////////
 
-  DiskUsageCounter::MountPointSet DiskUsageCounter::disk_usage(const ResPool &pool)
-  {
-    MountPointSet result = mps;
+  ///////////////////////////////////////////////////////////////////
+  namespace
+  { /////////////////////////////////////////////////////////////////
 
-    if (mps.empty())
+    struct SatMap : private base::NonCopyable
     {
-      // partitioning is not set
-      return result;
-    }
+      SatMap( unsigned capacity_r = 1 )
+      {
+        ::map_init( &_installedmap, sat::Pool::instance().capacity() );
+      }
 
-    // set used size after commit to the current used size
-    for (MountPointSet::iterator mpit = result.begin();
-      mpit != result.end();
-      mpit++)
-    {
-      mpit->pkg_size = mpit->used_size;
-    }
+      void add( sat::Solvable solv_r )
+      {
+        MAPSET( &_installedmap, solv_r.id() );
+      }
+
+      void add( const PoolItem & pi_r )
+      { add( pi_r->satSolvable() ); }
 
-    // iterate through all packages
-    for (ResPool::byKind_iterator it = pool.byKindBegin(ResTraits<Package>::kind);
-      it != pool.byKindEnd(ResTraits<Package>::kind);
-      ++it)
+      void add( const ResObject::constPtr & obj_r )
+      { add( obj_r->satSolvable() ); }
+
+      mutable ::Map _installedmap;
+    };
+
+    DiskUsageCounter::MountPointSet calcDiskUsage( const DiskUsageCounter::MountPointSet & mps_r, const SatMap & installedmap_r )
     {
-      bool inst = it->status().isToBeInstalled();
-      bool rem = it->status().isToBeUninstalled();
+      DiskUsageCounter::MountPointSet result = mps_r;
 
-      // if the package is not selected for installation or removing
-      // it can't affect disk usage
-      if (inst || rem)
+      if ( result.empty() )
       {
-       Package::constPtr pkg = asKind<Package>( it->resolvable() );
-       DiskUsage du = pkg->diskusage();
-       DiskUsage du_another_package;
-       Edition edition_another_package;
-
-       // the same package has been selected for installation
-       bool found_installed = false;
-       // the same package has been selected for uninstallation
-       bool found_to_install = false;
-
-       // the du is empty or the package is selected for installation (check whether the package is already installed)
-       if (du.size() == 0 || inst)
-       {
-           // disk usage is unknown for already installed packages
-           // find the same package from any installation source
-           std::string name = (*it)->name();
-
-           for (ResPool::byName_iterator nameit = pool.byNameBegin(name);
-             nameit != pool.byNameEnd(name);
-             ++nameit)
-           {
-               // is version and architecture same?
-               if (isKind<Package>(nameit->resolvable()))
-               {
-                   // found a package
-                   Package::constPtr pkg_from_source = asKind<Package>( nameit->resolvable() );
-
-                   if (nameit->status().isToBeInstalled())
-                   {
-                       found_to_install = true;
-                   }
-
-                   // check the version
-                   if ((*it)->edition() == (*nameit)->edition() && (*it)->arch() == (*nameit)->arch())
-                   {
-                       if (inst)
-                       {
-                           if (nameit->status().isInstalled() && !nameit->status().isToBeUninstalled())
-                           {
-                               found_installed = true;
-                               XXX << name << '-' << (*it)->edition() << ": found already installed package (" << (*nameit)->edition() << ")" << std::endl;
-                           }
-                       }
-                       else
-                       {
-                           // the package will be uninstalled and du is empty, try to use du from another object
-                           du = pkg_from_source->diskusage();
-                           if (du.size() > 0)
-                           {
-                               XXX << name << '-' << (*it)->edition() << ": using DiskUsage from another Package object (" << (*nameit)->edition() << ")" << std::endl;
-                               break;
-                           }
-                       }
-                   }
-                   else
-                   {
-                       if (inst && nameit->status().isInstalled() && !nameit->status().isToBeUninstalled())
-                       {
-                           // just freshen the package, don't change du statistics
-                           found_installed = true;
-                           XXX << name << '-' << (*it)->edition() << ": found already installed package (" << (*nameit)->edition() << ")" << std::endl;
-                       }
-                       else if (pkg_from_source->diskusage().size() > 0)
-                       {
-                           // found different version of the package, remember the disk usage
-                           // it will be used the same version is not found
-                           du_another_package = pkg_from_source->diskusage();
-                           edition_another_package = (*nameit)->edition();
-                       }
-                   }
-               }
-           }
+        // partitioning is not set
+        return result;
+      }
 
-           // don't subtract the disk usage for updated package
-           if (du.size() == 0 && du_another_package.size() > 0 && !(rem && found_to_install))
-           {
-               XXX << name << '-' << (*it)->edition() << ": using DU info from version " << edition_another_package << std::endl;
-               du = du_another_package;
-           }
-       }
+      sat::Pool satpool( sat::Pool::instance() );
+      if ( ! satpool.findSystemRepo() )
+      {
+        // take care we have at least an empty stystem repo.
+        // ::pool_calc_duchanges requires it.
+        satpool.systemRepo();
+        satpool.prepare();
+      }
 
-       // don't modify du if the installed package is already installed (freshening)
-       if (du.size() > 0 && !(inst && found_installed))
-       {
-         // iterate trough all mount points, add usage to each directory
-         // directory tree must be processed from leaves to the root directory
-         // so iterate in reverse order so e.g. /usr is used before /
-         for (MountPointSet::reverse_iterator mpit = result.rbegin();
-           mpit != result.rend();
-           mpit++)
-         {
-           // get usage for the mount point
-           DiskUsage::Entry entry = du.extract(mpit->dir);
-
-           // add or subtract it to the current value
-           if (inst)
-           {
-               mpit->pkg_size += entry._size;
-           }
-           else // the package will be uninstalled
-           {
-               mpit->pkg_size -= entry._size;
-           }
-         }
-       }
+      // init satsolver result vector with mountpoints
+      static const ::DUChanges _initdu = { 0, 0, 0 };
+      std::vector< ::DUChanges> duchanges( result.size(), _initdu );
+      {
+        unsigned idx = 0;
+        for_( it, result.begin(), result.end() )
+        {
+          duchanges[idx].path = it->dir.c_str();
+          ++idx;
+        }
       }
+
+      // now calc...
+      ::pool_calc_duchanges( satpool.get(),
+                             satpool.systemRepo().get(),
+                             &installedmap_r._installedmap,
+                             &duchanges[0],
+                             duchanges.size() );
+
+      // and process the result
+      {
+        unsigned idx = 0;
+        for_( it, result.begin(), result.end() )
+        {
+          static const ByteCount blockAdjust( 2, ByteCount::K ); // (files * blocksize) / (2 * 1K)
+
+          it->pkg_size = it->used_size          // current usage
+                       + duchanges[idx].kbytes  // package data size
+                       + ( duchanges[idx].files * it->block_size / blockAdjust ); // half block per file
+          ++idx;
+        }
+      }
+
+      return result;
     }
 
-    return result;
+    /////////////////////////////////////////////////////////////////
+  } // namespace
+  ///////////////////////////////////////////////////////////////////
+
+  DiskUsageCounter::MountPointSet DiskUsageCounter::disk_usage( const ResPool & pool_r )
+  {
+    SatMap installedmap( sat::Pool::instance().capacity() );
+    // build installedmap (installed != transact)
+    // stays installed or gets installed
+    for_( it, pool_r.begin(), pool_r.end() )
+    {
+      if ( it->status().isInstalled() != it->status().transacts() )
+      {
+        installedmap.add( *it );
+      }
+    }
+    return calcDiskUsage( mps, installedmap );
   }
 
+  DiskUsageCounter::MountPointSet DiskUsageCounter::disk_usage( sat::Solvable solv_r )
+  {
+    SatMap installedmap;
+    installedmap.add( solv_r );
+    return calcDiskUsage( mps, installedmap );
+  }
 
   DiskUsageCounter::MountPointSet DiskUsageCounter::detectMountPoints(const std::string &rootdir)
   {
@@ -242,6 +209,12 @@ namespace zypp
              continue;
            }
 
+           if ( words[2] == "vfat" || words[2] == "fat" || words[2] == "ntfs" || words[2] == "ntfs-3g")
+           {
+             MIL << words[1] << " contains ignored fs (" << words[2] << ')' << std::endl;
+             continue;
+           }
+
            //
            // Filter some common unwanted mountpoints
            //
@@ -303,11 +276,23 @@ namespace zypp
     return ret;
   }
 
+  DiskUsageCounter::MountPointSet DiskUsageCounter::justRootPartition()
+  {
+    DiskUsageCounter::MountPointSet ret;
+    ret.insert( DiskUsageCounter::MountPoint() );
+    return ret;
+  }
+
   std::ostream & operator<<( std::ostream & str, const DiskUsageCounter::MountPoint & obj )
   {
-    str << "dir:[" << obj.dir << "] [ bs: " << obj.block_size << " ts: " << obj.total_size << "]" << std::endl;
+     str << "dir:[" << obj.dir << "] [ bs: " << obj.blockSize()
+        << " ts: " << obj.totalSize()
+        << " us: " << obj.usedSize()
+        << " (+-: " << obj.commitDiff()
+        << ")]";
     return str;
   }
 
+  /////////////////////////////////////////////////////////////////
 } // namespace zypp
 ///////////////////////////////////////////////////////////////////