vfs: Use PinState in sync algorithm #6815
authorChristian Kamm <mail@ckamm.de>
Tue, 27 Nov 2018 09:22:23 +0000 (10:22 +0100)
committerKevin Ottens <kevin.ottens@nextcloud.com>
Tue, 15 Dec 2020 09:58:29 +0000 (10:58 +0100)
New files are virtual if the file's pin state is OnlineOnly.

src/libsync/discovery.cpp
src/libsync/discovery.h
test/testsyncvirtualfiles.cpp

index 1a1f5fad7d2f64953272c8c94a2ece5e05b59be6..64984f7ea137542a4251fb8938c68a94fab3056f 100644 (file)
@@ -400,7 +400,10 @@ void ProcessDirectoryJob::processFileAnalyzeRemoteInfo(
         }
         // Turn new remote files into virtual files if the option is enabled.
         auto &opts = _discoveryData->_syncOptions;
-        if (!localEntry.isValid() && opts._vfs->mode() != Vfs::Off && opts._newFilesAreVirtual && item->_type == ItemTypeFile) {
+        if (!localEntry.isValid()
+            && item->_type == ItemTypeFile
+            && opts._vfs->mode() != Vfs::Off
+            && directoryPinState() == PinState::OnlineOnly) {
             item->_type = ItemTypeVirtualFile;
             if (isVfsWithSuffix())
                 addVirtualFileSuffix(path._original);
@@ -1318,6 +1321,19 @@ bool ProcessDirectoryJob::runLocalQuery()
     return true;
 }
 
+PinState ProcessDirectoryJob::directoryPinState()
+{
+    if (_pinStateCache)
+        return *_pinStateCache;
+
+    // Get the path's pinstate and anchor to the root option
+    _pinStateCache = _discoveryData->_statedb->pinStateForPath(_currentFolder._original.toUtf8());
+    if (*_pinStateCache == PinState::Unspecified)
+        _pinStateCache = _discoveryData->_syncOptions._newFilesAreVirtual ? PinState::OnlineOnly : PinState::AlwaysLocal;
+
+    return *_pinStateCache;
+}
+
 bool ProcessDirectoryJob::isVfsWithSuffix() const
 {
     return _discoveryData->_syncOptions._vfs->mode() == Vfs::WithSuffix;
index 7927077a86831b7cf863d122580df6086eb2ab89..99d0013b12f5a6ad0e540c88e83077b9c7011328 100644 (file)
@@ -18,6 +18,7 @@
 #include "discoveryphase.h"
 #include "syncfileitem.h"
 #include "common/asserts.h"
+#include "common/syncjournaldb.h"
 
 class ExcludedFiles;
 
@@ -177,6 +178,9 @@ private:
       */
     bool runLocalQuery();
 
+    /** Retrieve and cache directory pin state */
+    PinState directoryPinState();
+
     QueryMode _queryServer;
     QueryMode _queryLocal;
 
@@ -216,6 +220,7 @@ private:
     PathTuple _currentFolder;
     bool _childModified = false; // the directory contains modified item what would prevent deletion
     bool _childIgnored = false; // The directory contains ignored item that would prevent deletion
+    Optional<PinState> _pinStateCache; // The directories pin-state, once retrieved, see directoryPinState()
 
 signals:
     void finished();
index b1f5d53f14ef8ac11b20932a5bd0351ce27681b3..cc38527a92d67d5eda7f8127abe21cc995ee8b07 100644 (file)
@@ -739,6 +739,61 @@ private slots:
         QVERIFY(fakeFolder.currentRemoteState().find("A/a3.nextcloud")); // regular upload
         QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
     }
+
+    void testNewVirtuals()
+    {
+        FakeFolder fakeFolder{ FileInfo() };
+        SyncOptions syncOptions = vfsSyncOptions();
+        syncOptions._newFilesAreVirtual = true;
+        fakeFolder.syncEngine().setSyncOptions(syncOptions);
+        QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
+
+        auto setPin = [&] (const QByteArray &path, PinState state) {
+            fakeFolder.syncJournal().setPinStateForPath(path, state);
+        };
+
+        fakeFolder.remoteModifier().mkdir("local");
+        fakeFolder.remoteModifier().mkdir("online");
+        fakeFolder.remoteModifier().mkdir("unspec");
+        QVERIFY(fakeFolder.syncOnce());
+        QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
+
+        setPin("local", PinState::AlwaysLocal);
+        setPin("online", PinState::OnlineOnly);
+
+        // Test 1: root is OnlineOnly
+        fakeFolder.remoteModifier().insert("file1");
+        fakeFolder.remoteModifier().insert("online/file1");
+        fakeFolder.remoteModifier().insert("local/file1");
+        fakeFolder.remoteModifier().insert("unspec/file1");
+        QVERIFY(fakeFolder.syncOnce());
+
+        QVERIFY(fakeFolder.currentLocalState().find("file1.nextcloud"));
+        QVERIFY(fakeFolder.currentLocalState().find("online/file1.nextcloud"));
+        QVERIFY(fakeFolder.currentLocalState().find("local/file1"));
+        QVERIFY(fakeFolder.currentLocalState().find("unspec/file1.nextcloud"));
+
+        // Test 2: root is AlwaysLocal
+        syncOptions._newFilesAreVirtual = false;
+        fakeFolder.syncEngine().setSyncOptions(syncOptions);
+
+        fakeFolder.remoteModifier().insert("file2");
+        fakeFolder.remoteModifier().insert("online/file2");
+        fakeFolder.remoteModifier().insert("local/file2");
+        fakeFolder.remoteModifier().insert("unspec/file2");
+        QVERIFY(fakeFolder.syncOnce());
+
+        QVERIFY(fakeFolder.currentLocalState().find("file2"));
+        QVERIFY(fakeFolder.currentLocalState().find("online/file2.nextcloud"));
+        QVERIFY(fakeFolder.currentLocalState().find("local/file2"));
+        QVERIFY(fakeFolder.currentLocalState().find("unspec/file2"));
+
+        // file1 is unchanged
+        QVERIFY(fakeFolder.currentLocalState().find("file1.nextcloud"));
+        QVERIFY(fakeFolder.currentLocalState().find("online/file1.nextcloud"));
+        QVERIFY(fakeFolder.currentLocalState().find("local/file1"));
+        QVERIFY(fakeFolder.currentLocalState().find("unspec/file1.nextcloud"));
+    }
 };
 
 QTEST_GUILESS_MAIN(TestSyncVirtualFiles)