1 From 9c0dc6b3f0826d32eac310b2e7ecd858ca3df681 Mon Sep 17 00:00:00 2001
2 From: =?UTF-8?q?Dan=20Vr=C3=A1til?= <dvratil@redhat.com>
3 Date: Mon, 29 Jun 2015 22:45:11 +0200
4 Subject: [PATCH 33/34] Don't leak old external payload files
6 Actually delete old payload files after we increase the payload revision or
7 switch from external to internal payload. This caused ~/.local/share/akonadi/file_db_data
8 to grow insanely for all users, leaving them with many duplicated files (just with
11 It is recommended that users run akonadictl fsck to clean up the leaked payload
14 Note that there won't be any more releases of Akonadi 1.13 (and this has been
15 fixed in master already), so I strongly recommend distributions to pick this
16 patch into their packaging.
21 server/src/storage/partstreamer.cpp | 14 ++++++++++++++
22 server/tests/unittest/partstreamertest.cpp | 24 +++++++++++++-----------
23 2 files changed, 27 insertions(+), 11 deletions(-)
25 diff --git a/server/src/storage/partstreamer.cpp b/server/src/storage/partstreamer.cpp
26 index 2ec41fa..71bdca8 100644
27 --- a/server/src/storage/partstreamer.cpp
28 +++ b/server/src/storage/partstreamer.cpp
29 @@ -290,6 +290,12 @@ bool PartStreamer::stream(const QByteArray &command, bool checkExists,
33 + // If the part is external, remember it's current file name
34 + QString originalFile;
35 + if (part.isValid() && part.external()) {
36 + originalFile = PartHelper::resolveAbsolutePath(part.data());
39 part.setPartType(partType);
40 part.setVersion(partVersion);
41 part.setPimItemId(mItem.id());
42 @@ -306,6 +312,14 @@ bool PartStreamer::stream(const QByteArray &command, bool checkExists,
43 *changed = mDataChanged;
46 + if (!originalFile.isEmpty()) {
47 + // If the part was external but is not anymore, or if it's still external
48 + // but the filename has changed (revision update), remove the original file
49 + if (!part.external() || (part.external() && originalFile != PartHelper::resolveAbsolutePath(part.data()))) {
50 + PartHelper::removeFile(originalFile);
57 diff --git a/server/tests/unittest/partstreamertest.cpp b/server/tests/unittest/partstreamertest.cpp
58 index 05e3a8a..669bbbc 100644
59 --- a/server/tests/unittest/partstreamertest.cpp
60 +++ b/server/tests/unittest/partstreamertest.cpp
61 @@ -91,6 +91,7 @@ private Q_SLOTS:
62 QTest::addColumn<qint64>("expectedPartSize");
63 QTest::addColumn<bool>("expectedChanged");
64 QTest::addColumn<bool>("isExternal");
65 + QTest::addColumn<int>("version");
66 QTest::addColumn<PimItem>("pimItem");
69 @@ -101,22 +102,22 @@ private Q_SLOTS:
70 QVERIFY(item.insert());
72 // Order of these tests matters!
73 - QTest::newRow("item 1, internal") << QByteArray("PLD:DATA") << QByteArray("123") << 3ll << true << false << item;
74 - QTest::newRow("item 1, change to external") << QByteArray("PLD:DATA") << QByteArray("123456789") << 9ll << true << true << item;
75 - QTest::newRow("item 1, update external") << QByteArray("PLD:DATA") << QByteArray("987654321") << 9ll << true << true << item;
76 - QTest::newRow("item 1, external, no change") << QByteArray("PLD:DATA") << QByteArray("987654321") << 9ll << false << true << item;
77 - QTest::newRow("item 1, change to internal") << QByteArray("PLD:DATA") << QByteArray("1234") << 4ll << true << false << item;
78 - QTest::newRow("item 1, internal, no change") << QByteArray("PLD:DATA") << QByteArray("1234") << 4ll << false << false << item;
79 + QTest::newRow("item 1, internal") << QByteArray("PLD:DATA") << QByteArray("123") << 3ll << true << false << -1 << item;
80 + QTest::newRow("item 1, change to external") << QByteArray("PLD:DATA") << QByteArray("123456789") << 9ll << true << true << 0 << item;
81 + QTest::newRow("item 1, update external") << QByteArray("PLD:DATA") << QByteArray("987654321") << 9ll << true << true << 1 << item;
82 + QTest::newRow("item 1, external, no change") << QByteArray("PLD:DATA") << QByteArray("987654321") << 9ll << false << true << 2 << item;
83 + QTest::newRow("item 1, change to internal") << QByteArray("PLD:DATA") << QByteArray("1234") << 4ll << true << false << 2 << item;
84 + QTest::newRow("item 1, internal, no change") << QByteArray("PLD:DATA") << QByteArray("1234") << 4ll << false << false << 2 << item;
90 QFETCH(QByteArray, expectedPartName);
91 QFETCH(QByteArray, expectedData);
92 QFETCH(qint64, expectedPartSize);
93 QFETCH(bool, expectedChanged);
94 QFETCH(bool, isExternal);
95 + QFETCH(int, version);
96 QFETCH(PimItem, pimItem);
98 FakeConnection connection;
99 @@ -160,17 +161,18 @@ private Q_SLOTS:
101 PimItem item = PimItem::retrieveById(pimItem.id());
102 const QVector<Part> parts = item.parts();
103 - QVERIFY(parts.count() == 1);
104 + QCOMPARE(parts.count(), 1);
105 const Part part = parts[0];
106 QCOMPARE(part.datasize(), expectedPartSize);
107 QCOMPARE(part.external(), isExternal);
108 + qDebug() << part.version() << part.data();
109 const QByteArray data = part.data();
111 QVERIFY(streamerSpy.count() == 1);
112 QVERIFY(streamerSpy.first().count() == 1);
113 const Response response = streamerSpy.first().first().value<Akonadi::Server::Response>();
114 const QByteArray str = response.asString();
115 - const QByteArray expectedResponse = "+ STREAM [FILE " + QByteArray::number(part.id()) + "_r" + QByteArray::number(part.version()) + "]";
116 + const QByteArray expectedResponse = "+ STREAM [FILE " + QByteArray::number(part.id()) + "_r" + QByteArray::number(version) + "]";
117 QCOMPARE(QString::fromUtf8(str), QString::fromUtf8(expectedResponse));
119 QFile file(PartHelper::resolveAbsolutePath(data));
120 @@ -182,7 +184,7 @@ private Q_SLOTS:
121 QCOMPARE(fileData, expectedData);
123 // Make sure no previous versions are left behind in file_db_data
124 - for (int i = 0; i < part.version(); ++i) {
125 + for (int i = 0; i < version; ++i) {
126 const QByteArray fileName = QByteArray::number(part.id()) + "_r" + QByteArray::number(part.version());
127 const QString filePath = PartHelper::resolveAbsolutePath(fileName);
128 QVERIFY(!QFile::exists(filePath));
129 @@ -194,7 +196,7 @@ private Q_SLOTS:
130 QCOMPARE(data, expectedData);
132 // Make sure nothing is left behind in file_db_data
133 - for (int i = 0; i <= part.version(); ++i) {
134 + for (int i = 0; i <= version; ++i) {
135 const QByteArray fileName = QByteArray::number(part.id()) + "_r" + QByteArray::number(part.version());
136 const QString filePath = PartHelper::resolveAbsolutePath(fileName);
137 QVERIFY(!QFile::exists(filePath));