Преглед на файлове

Vfs: "free space" only shows when it has an effect #7143

To do this, introduce AllDehydrated availability and rename
SomeDehydrated to Mixed - it now guarantees there are also hydrated
items.
Christian Kamm преди 6 години
родител
ревизия
7f3f13fd97
променени са 9 файла, в които са добавени 69 реда и са изтрити 46 реда
  1. 11 5
      src/common/pinstate.h
  2. 17 8
      src/common/syncjournaldb.cpp
  3. 8 1
      src/common/syncjournaldb.h
  4. 6 4
      src/common/vfs.cpp
  5. 4 2
      src/gui/accountsettings.cpp
  6. 5 7
      src/gui/guiutility.cpp
  7. 1 1
      src/gui/guiutility.h
  8. 11 14
      src/gui/socketapi.cpp
  9. 6 4
      test/testsyncvirtualfiles.cpp

+ 11 - 5
src/common/pinstate.h

@@ -83,13 +83,15 @@ enum class PinState {
  *
  * Note that this is only about *intent*. The file could still be out of date,
  * or not have been synced for other reasons, like errors.
+ *
+ * NOTE: The numerical values and ordering of this enum are relevant.
  */
 enum class VfsItemAvailability {
     /** The item and all its subitems are hydrated and pinned AlwaysLocal.
      *
      * This guarantees that all contents will be kept in sync.
      */
-    AlwaysLocal,
+    AlwaysLocal = 0,
 
     /** The item and all its subitems are hydrated.
      *
@@ -98,20 +100,24 @@ enum class VfsItemAvailability {
      *
      * A folder with no file contents will have this availability.
      */
-    AllHydrated,
+    AllHydrated = 1,
 
-    /** There are dehydrated items but the pin state isn't all OnlineOnly.
+    /** There are dehydrated and hydrated items.
      *
      * This would happen if a dehydration happens to a Unspecified item that
      * used to be hydrated.
      */
-    SomeDehydrated,
+    Mixed = 2,
+
+    /** There are only dehydrated items but the pin state isn't all OnlineOnly.
+     */
+    AllDehydrated = 3,
 
     /** The item and all its subitems are dehydrated and OnlineOnly.
      *
      * This guarantees that contents will not take up space.
      */
-    OnlineOnly,
+    OnlineOnly = 4,
 };
 
 }

+ 17 - 8
src/common/syncjournaldb.cpp

@@ -1328,18 +1328,16 @@ bool SyncJournalDb::updateLocalMetadata(const QString &filename,
     return _setFileRecordLocalMetadataQuery.exec();
 }
 
-Optional<bool> SyncJournalDb::hasDehydratedFiles(const QByteArray &filename)
+Optional<SyncJournalDb::HasHydratedDehydrated> SyncJournalDb::hasHydratedOrDehydratedFiles(const QByteArray &filename)
 {
     QMutexLocker locker(&_mutex);
     if (!checkConnect())
         return {};
 
     auto &query = _countDehydratedFilesQuery;
-    static_assert(ItemTypeVirtualFile == 4 && ItemTypeVirtualFileDownload == 5, "");
     if (!query.initOrReset(QByteArrayLiteral(
-            "SELECT count(*) FROM metadata"
-            " WHERE (" IS_PREFIX_PATH_OR_EQUAL("?1", "path") " OR ?1 == '')"
-            " AND (type == 4 OR type == 5);"), _db)) {
+            "SELECT DISTINCT type FROM metadata"
+            " WHERE (" IS_PREFIX_PATH_OR_EQUAL("?1", "path") " OR ?1 == '');"), _db)) {
         return {};
     }
 
@@ -1347,10 +1345,21 @@ Optional<bool> SyncJournalDb::hasDehydratedFiles(const QByteArray &filename)
     if (!query.exec())
         return {};
 
-    if (!query.next().hasData)
-        return {};
+    HasHydratedDehydrated result;
+    forever {
+        auto next = query.next();
+        if (!next.ok)
+            return {};
+        if (!next.hasData)
+            break;
+        auto type = static_cast<ItemType>(query.intValue(0));
+        if (type == ItemTypeFile || type == ItemTypeVirtualFileDehydration)
+            result.hasHydrated = true;
+        if (type == ItemTypeVirtualFile || type == ItemTypeVirtualFileDownload)
+            result.hasDehydrated = true;
+    }
 
-    return query.intValue(0) > 0;
+    return result;
 }
 
 static void toDownloadInfo(SqlQuery &query, SyncJournalDb::DownloadInfo *res)

+ 8 - 1
src/common/syncjournaldb.h

@@ -73,8 +73,15 @@ public:
     bool updateLocalMetadata(const QString &filename,
         qint64 modtime, qint64 size, quint64 inode);
 
+    /// Return value for hasHydratedOrDehydratedFiles()
+    struct HasHydratedDehydrated
+    {
+        bool hasHydrated = false;
+        bool hasDehydrated = false;
+    };
+
     /** Returns whether the item or any subitems are dehydrated */
-    Optional<bool> hasDehydratedFiles(const QByteArray &filename);
+    Optional<HasHydratedDehydrated> hasHydratedOrDehydratedFiles(const QByteArray &filename);
 
     bool exists();
     void walCheckpoint();

+ 6 - 4
src/common/vfs.cpp

@@ -83,15 +83,17 @@ Optional<VfsItemAvailability> Vfs::availabilityInDb(const QString &folderPath, c
 {
     auto pin = _setupParams.journal->internalPinStates().effectiveForPathRecursive(pinPath.toUtf8());
     // not being able to retrieve the pin state isn't too bad
-    Optional<bool> hasDehydrated = _setupParams.journal->hasDehydratedFiles(folderPath.toUtf8());
-    if (!hasDehydrated)
+    auto hydrationStatus = _setupParams.journal->hasHydratedOrDehydratedFiles(folderPath.toUtf8());
+    if (!hydrationStatus)
         return {};
 
-    if (*hasDehydrated) {
+    if (hydrationStatus->hasDehydrated) {
+        if (hydrationStatus->hasHydrated)
+            return VfsItemAvailability::Mixed;
         if (pin && *pin == PinState::OnlineOnly)
             return VfsItemAvailability::OnlineOnly;
         else
-            return VfsItemAvailability::SomeDehydrated;
+            return VfsItemAvailability::AllDehydrated;
     } else {
         if (pin && *pin == PinState::AlwaysLocal)
             return VfsItemAvailability::AlwaysLocal;

+ 4 - 2
src/gui/accountsettings.cpp

@@ -449,7 +449,7 @@ void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos)
         auto availabilityMenu = menu->addMenu(tr("Availability"));
         auto availability = folder->vfs().availability(QString());
         if (availability) {
-            ac = availabilityMenu->addAction(Utility::vfsCurrentAvailabilityText(*availability, true));
+            ac = availabilityMenu->addAction(Utility::vfsCurrentAvailabilityText(*availability));
             ac->setEnabled(false);
         }
 
@@ -458,7 +458,9 @@ void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos)
         connect(ac, &QAction::triggered, this, [this]() { slotSetCurrentFolderAvailability(PinState::AlwaysLocal); });
 
         ac = availabilityMenu->addAction(Utility::vfsFreeSpaceActionText());
-        ac->setEnabled(!availability || *availability != VfsItemAvailability::OnlineOnly);
+        ac->setEnabled(!availability
+                || !(*availability == VfsItemAvailability::OnlineOnly
+                    || *availability == VfsItemAvailability::AllDehydrated));
         connect(ac, &QAction::triggered, this, [this]() { slotSetCurrentFolderAvailability(PinState::OnlineOnly); });
 
         ac = menu->addAction(tr("Disable virtual file support..."));

+ 5 - 7
src/gui/guiutility.cpp

@@ -69,19 +69,17 @@ bool Utility::openEmailComposer(const QString &subject, const QString &body, QWi
     return true;
 }
 
-QString Utility::vfsCurrentAvailabilityText(VfsItemAvailability availability, bool forFolder)
+QString Utility::vfsCurrentAvailabilityText(VfsItemAvailability availability)
 {
     switch(availability) {
     case VfsItemAvailability::AlwaysLocal:
         return QCoreApplication::translate("utility", "Currently always available locally");
     case VfsItemAvailability::AllHydrated:
         return QCoreApplication::translate("utility", "Currently available locally");
-    case VfsItemAvailability::SomeDehydrated:
-        if (forFolder) {
-            return QCoreApplication::translate("utility", "Currently some available online only");
-        } else {
-            return QCoreApplication::translate("utility", "Currently available online only");
-        }
+    case VfsItemAvailability::Mixed:
+        return QCoreApplication::translate("utility", "Currently some available online only");
+    case VfsItemAvailability::AllDehydrated:
+        return QCoreApplication::translate("utility", "Currently available online only");
     case VfsItemAvailability::OnlineOnly:
         return QCoreApplication::translate("utility", "Currently available online only");
     }

+ 1 - 1
src/gui/guiutility.h

@@ -41,7 +41,7 @@ namespace Utility {
      *
      * This will be used in context menus to describe the current state.
      */
-    QString vfsCurrentAvailabilityText(VfsItemAvailability availability, bool forFolder);
+    QString vfsCurrentAvailabilityText(VfsItemAvailability availability);
 
     /** Translated text for "making items always available locally" */
     QString vfsPinActionText();

+ 11 - 14
src/gui/socketapi.cpp

@@ -1049,19 +1049,19 @@ void SocketApi::command_GET_MENU_ITEMS(const QString &argument, OCC::SocketListe
         auto merge = [](VfsItemAvailability lhs, VfsItemAvailability rhs) {
             if (lhs == rhs)
                 return lhs;
-            if (lhs == VfsItemAvailability::SomeDehydrated || rhs == VfsItemAvailability::SomeDehydrated
-                || lhs == VfsItemAvailability::OnlineOnly || rhs == VfsItemAvailability::OnlineOnly) {
-                return VfsItemAvailability::SomeDehydrated;
-            }
-            return VfsItemAvailability::AllHydrated;
+            auto l = int(lhs) < int(rhs) ? lhs : rhs; // reduce cases by sorting
+            auto r = int(lhs) < int(rhs) ? rhs : lhs;
+            if (l == VfsItemAvailability::AlwaysLocal && r == VfsItemAvailability::AllHydrated)
+                return VfsItemAvailability::AllHydrated;
+            if (l == VfsItemAvailability::AllDehydrated && r == VfsItemAvailability::OnlineOnly)
+                return VfsItemAvailability::AllDehydrated;
+            return VfsItemAvailability::Mixed;
         };
-        bool isFolderOrMultiple = false;
         for (const auto &file : files) {
             auto fileData = FileData::get(file);
-            isFolderOrMultiple = QFileInfo(fileData.localPath).isDir();
             auto availability = syncFolder->vfs().availability(fileData.folderRelativePath);
             if (!availability)
-                availability = VfsItemAvailability::SomeDehydrated; // db error
+                availability = VfsItemAvailability::Mixed; // db error
             if (!combined) {
                 combined = availability;
             } else {
@@ -1069,13 +1069,11 @@ void SocketApi::command_GET_MENU_ITEMS(const QString &argument, OCC::SocketListe
             }
         }
         ENFORCE(combined);
-        if (files.size() > 1)
-            isFolderOrMultiple = true;
 
         // TODO: Should be a submenu, should use icons
         auto makePinContextMenu = [&](bool makeAvailableLocally, bool freeSpace) {
             listener->sendMessage(QLatin1String("MENU_ITEM:CURRENT_PIN:d:")
-                                  + Utility::vfsCurrentAvailabilityText(*combined, isFolderOrMultiple));
+                                  + Utility::vfsCurrentAvailabilityText(*combined));
             listener->sendMessage(QLatin1String("MENU_ITEM:MAKE_AVAILABLE_LOCALLY:")
                                   + (makeAvailableLocally ? QLatin1String(":") : QLatin1String("d:"))
                                   + Utility::vfsPinActionText());
@@ -1089,11 +1087,10 @@ void SocketApi::command_GET_MENU_ITEMS(const QString &argument, OCC::SocketListe
             makePinContextMenu(false, true);
             break;
         case VfsItemAvailability::AllHydrated:
+        case VfsItemAvailability::Mixed:
             makePinContextMenu(true, true);
             break;
-        case VfsItemAvailability::SomeDehydrated:
-            makePinContextMenu(true, true);
-            break;
+        case VfsItemAvailability::AllDehydrated:
         case VfsItemAvailability::OnlineOnly:
             makePinContextMenu(true, false);
             break;

+ 6 - 4
test/testsyncvirtualfiles.cpp

@@ -1061,21 +1061,23 @@ private slots:
         QCOMPARE(*vfs->availability("local/file1"), VfsItemAvailability::AlwaysLocal);
         QCOMPARE(*vfs->availability("online"), VfsItemAvailability::OnlineOnly);
         QCOMPARE(*vfs->availability("online/file1.nextcloud"), VfsItemAvailability::OnlineOnly);
-        QCOMPARE(*vfs->availability("unspec"), VfsItemAvailability::SomeDehydrated);
-        QCOMPARE(*vfs->availability("unspec/file1.nextcloud"), VfsItemAvailability::SomeDehydrated);
+        QCOMPARE(*vfs->availability("unspec"), VfsItemAvailability::AllDehydrated);
+        QCOMPARE(*vfs->availability("unspec/file1.nextcloud"), VfsItemAvailability::AllDehydrated);
 
         // Subitem pin states can ruin "pure" availabilities
         setPin("local/sub", PinState::OnlineOnly);
         QCOMPARE(*vfs->availability("local"), VfsItemAvailability::AllHydrated);
         setPin("online/sub", PinState::Unspecified);
-        QCOMPARE(*vfs->availability("online"), VfsItemAvailability::SomeDehydrated);
+        QCOMPARE(*vfs->availability("online"), VfsItemAvailability::AllDehydrated);
 
         triggerDownload(fakeFolder, "unspec/file1");
         setPin("local/file2", PinState::OnlineOnly);
+        setPin("online/file2", PinState::AlwaysLocal);
         QVERIFY(fakeFolder.syncOnce());
 
         QCOMPARE(*vfs->availability("unspec"), VfsItemAvailability::AllHydrated);
-        QCOMPARE(*vfs->availability("local"), VfsItemAvailability::SomeDehydrated);
+        QCOMPARE(*vfs->availability("local"), VfsItemAvailability::Mixed);
+        QCOMPARE(*vfs->availability("online"), VfsItemAvailability::Mixed);
 
         vfs->setPinState("local", PinState::AlwaysLocal);
         vfs->setPinState("online", PinState::OnlineOnly);