Merge lp:~mzanetti/reminders-app/fix-writeback-issue into lp:reminders-app

Proposed by Michael Zanetti on 2015-07-05
Status: Merged
Approved by: Riccardo Padovani on 2015-09-08
Approved revision: 469
Merged at revision: 483
Proposed branch: lp:~mzanetti/reminders-app/fix-writeback-issue
Merge into: lp:reminders-app
Diff against target: 274 lines (+82/-38)
7 files modified
src/app/qml/reminders.qml (+27/-24)
src/app/qml/ui/NoteView.qml (+12/-2)
src/libqtevernote/evernoteconnection.cpp (+18/-1)
src/libqtevernote/evernoteconnection.h (+4/-0)
src/libqtevernote/jobs/savenotejob.cpp (+10/-1)
src/libqtevernote/jobs/savenotejob.h (+2/-0)
src/libqtevernote/notesstore.cpp (+9/-10)
To merge this branch: bzr merge lp:~mzanetti/reminders-app/fix-writeback-issue
Reviewer Review Type Date Requested Status
Riccardo Padovani 2015-07-05 Approve on 2015-09-08
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve on 2015-09-08
Review via email: mp+263848@code.launchpad.net

Commit Message

some improvements in job handling:

* treat write operations with highest priority
* don't dedupe or reorder write operations
* don't update the local note after a write operation. that will break local changes while the write operation is running.

To post a comment you must log in.
468. By Michael Zanetti on 2015-07-05

more fixes

* handle multiple push notifications at once
* fix lastSyncSequenceNumber
* don't write back every checkbox change immediately, only when exiting

Riccardo Padovani (rpadovani) wrote :

Looks good to me, just a couple of comments inline (clarification, nothing wrong)

review: Needs Information
Michael Zanetti (mzanetti) :
Michael Terry (mterry) wrote :

I'm not sure if this helped with my problem (bug 1487920)...

I tried this branch, and while it looked like it was trying to save (which is better than before!), it wasn't super successful:

[0824/120454:WARNING:channel.cc(549)] Failed to send message to ack remove remote endpoint (local ID 1, remote ID 1)
[0824/120454:WARNING:channel.cc(315)] RawChannel write error

Michael Zanetti (mzanetti) wrote :

interesting... no idea where that message comes from.

469. By Michael Zanetti on 2015-08-23

revert unwanted change

PASSED: Continuous integration, rev:469
http://91.189.93.70:8080/job/reminders-app-ci/778/
Executed test runs:
    SUCCESS: http://91.189.93.70:8080/job/reminders-app-vivid-amd64-ci/200

Click here to trigger a rebuild:
http://91.189.93.70:8080/job/reminders-app-ci/778/rebuild

review: Approve (continuous-integration)
Riccardo Padovani (rpadovani) wrote :

lgtm, thanks!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/app/qml/reminders.qml'
2--- src/app/qml/reminders.qml 2015-07-25 03:01:39 +0000
3+++ src/app/qml/reminders.qml 2015-09-08 16:22:25 +0000
4@@ -360,32 +360,35 @@
5 appId: root.applicationName + "_reminders"
6
7 onNotificationsChanged: {
8- print("PushClient notification:", notifications)
9- var notification = JSON.parse(notifications)["payload"];
10-
11- if (notification["userId"] != UserStore.userId) { // Yes, we want type coercion here.
12- console.warn("user mismatch:", notification["userId"], "!=", UserStore.userId)
13- return;
14- }
15-
16- switch(notification["reason"]) {
17- case "update":
18- print("Note updated on server:", notification["guid"])
19- if (NotesStore.note(notification["guid"]) === null) {
20+ print("Received PushClient notifications:", notifications.length)
21+ for (var i = 0; i < notifications.length; i++) {
22+ print("notification", i, ":", notifications[i])
23+ var notification = JSON.parse(notifications[i])["payload"];
24+
25+ if (notification["userId"] != UserStore.userId) { // Yes, we want type coercion here.
26+ console.warn("user mismatch:", notification["userId"], "!=", UserStore.userId)
27+ return;
28+ }
29+
30+ switch(notification["reason"]) {
31+ case "update":
32+ print("Note updated on server:", notification["guid"])
33+ if (NotesStore.note(notification["guid"]) === null) {
34+ NotesStore.refreshNotes();
35+ } else {
36+ NotesStore.refreshNoteContent(notification["guid"]);
37+ }
38+ break;
39+ case "create":
40+ print("New note appeared on server:", notification["guid"])
41 NotesStore.refreshNotes();
42- } else {
43- NotesStore.refreshNoteContent(notification["guid"]);
44+ break;
45+ case "notebook_update":
46+ NotesStore.refreshNotebooks();
47+ break;
48+ default:
49+ console.warn("Unhandled push notification:", notification["reason"])
50 }
51- break;
52- case "create":
53- print("New note appeared on server:", notification["guid"])
54- NotesStore.refreshNotes();
55- break;
56- case "notebook_update":
57- NotesStore.refreshNotebooks();
58- break;
59- default:
60- console.warn("Unhandled push notification:", notification["reason"])
61 }
62 }
63
64
65=== modified file 'src/app/qml/ui/NoteView.qml'
66--- src/app/qml/ui/NoteView.qml 2015-07-25 01:52:22 +0000
67+++ src/app/qml/ui/NoteView.qml 2015-09-08 16:22:25 +0000
68@@ -39,6 +39,17 @@
69 z: 10
70 }
71
72+ Component.onDestruction: {
73+ if (priv.dirty) {
74+ NotesStore.saveNote(note.guid);
75+ }
76+ }
77+
78+ QtObject {
79+ id: priv
80+ property bool dirty: false
81+ }
82+
83 WebContext {
84 id: webContext
85
86@@ -81,7 +92,6 @@
87
88 locationBarController {
89 height: locationBar.height
90- mode: Oxide.LocationBarController.ModeAuto
91 }
92
93 property string html: root.note ? note.htmlContent : ""
94@@ -111,7 +121,7 @@
95 switch (data.type) {
96 case "checkboxChanged":
97 note.markTodo(data.todoId, data.checked);
98- NotesStore.saveNote(note.guid);
99+ priv.dirty = true;
100 break;
101 case "attachmentOpened":
102 var filePath = root.note.resource(data.resourceHash).hashedFilePath;
103
104=== modified file 'src/libqtevernote/evernoteconnection.cpp'
105--- src/libqtevernote/evernoteconnection.cpp 2015-03-30 19:01:49 +0000
106+++ src/libqtevernote/evernoteconnection.cpp 2015-09-08 16:22:25 +0000
107@@ -446,6 +446,7 @@
108 }
109 return;
110 }
111+
112 EvernoteJob *existingJob = findExistingDuplicate(job);
113 if (existingJob) {
114 qCDebug(dcJobQueue) << "Duplicate job already queued:" << job->toString();
115@@ -491,6 +492,20 @@
116 }
117 }
118
119+void EvernoteConnection::enqueueWrite(EvernoteJob *job)
120+{
121+ if (!isConnected()) {
122+ qCWarning(dcJobQueue) << "Not connected to evernote. Can't enqueue job.";
123+ job->emitJobDone(ErrorCodeConnectionLost, gettext("Disconnected from Evernote."));
124+ job->deleteLater();
125+ return;
126+ }
127+ connect(job, &EvernoteJob::jobFinished, job, &EvernoteJob::deleteLater);
128+ connect(job, &EvernoteJob::jobFinished, this, &EvernoteConnection::startNextJob);
129+ m_writeJobQueue.append(job);
130+ startJobQueue();
131+}
132+
133 bool EvernoteConnection::isConnected() const
134 {
135 return m_userstoreClient != nullptr &&
136@@ -512,7 +527,9 @@
137 return;
138 }
139
140- if (!m_highPriorityJobQueue.isEmpty()) {
141+ if (!m_writeJobQueue.isEmpty()) {
142+ m_currentJob = m_writeJobQueue.takeFirst();
143+ } else if (!m_highPriorityJobQueue.isEmpty()) {
144 m_currentJob = m_highPriorityJobQueue.takeFirst();
145 } else if (!m_mediumPriorityJobQueue.isEmpty()){
146 m_currentJob = m_mediumPriorityJobQueue.takeFirst();
147
148=== modified file 'src/libqtevernote/evernoteconnection.h'
149--- src/libqtevernote/evernoteconnection.h 2015-03-08 21:29:28 +0000
150+++ src/libqtevernote/evernoteconnection.h 2015-09-08 16:22:25 +0000
151@@ -88,6 +88,9 @@
152 // multiple times.
153 void enqueue(EvernoteJob *job);
154
155+ // Use this to queue write calls. They won't be deduped and will be ordered
156+ void enqueueWrite(EvernoteJob *job);
157+
158 bool isConnected() const;
159
160 QString error() const;
161@@ -134,6 +137,7 @@
162 QList<EvernoteJob*> m_highPriorityJobQueue;
163 QList<EvernoteJob*> m_mediumPriorityJobQueue;
164 QList<EvernoteJob*> m_lowPriorityJobQueue;
165+ QList<EvernoteJob*> m_writeJobQueue;
166 EvernoteJob *m_currentJob;
167
168 // Those need to be mutexed
169
170=== modified file 'src/libqtevernote/jobs/savenotejob.cpp'
171--- src/libqtevernote/jobs/savenotejob.cpp 2015-03-15 20:00:21 +0000
172+++ src/libqtevernote/jobs/savenotejob.cpp 2015-09-08 16:22:25 +0000
173@@ -37,7 +37,8 @@
174 if (!otherJob) {
175 return false;
176 }
177- return this->m_note == otherJob->m_note;
178+ return this->m_note == otherJob->m_note
179+ && this->m_note->updateSequenceNumber() == otherJob->m_note->updateSequenceNumber();
180 }
181
182 void SaveNoteJob::attachToDuplicate(const EvernoteJob *other)
183@@ -46,6 +47,14 @@
184 connect(otherJob, &SaveNoteJob::jobDone, this, &SaveNoteJob::jobDone);
185 }
186
187+QString SaveNoteJob::toString() const
188+{
189+ return QString("%1, NoteGuid: %2, UpdateSeq: %3")
190+ .arg(metaObject()->className())
191+ .arg(m_note->guid())
192+ .arg(m_note->updateSequenceNumber());
193+}
194+
195 void SaveNoteJob::startJob()
196 {
197 evernote::edam::Note note;
198
199=== modified file 'src/libqtevernote/jobs/savenotejob.h'
200--- src/libqtevernote/jobs/savenotejob.h 2014-10-24 18:45:35 +0000
201+++ src/libqtevernote/jobs/savenotejob.h 2015-09-08 16:22:25 +0000
202@@ -34,6 +34,8 @@
203 virtual bool operator==(const EvernoteJob *other) const override;
204 virtual void attachToDuplicate(const EvernoteJob *other) override;
205
206+ virtual QString toString() const override;
207+
208 signals:
209 void jobDone(EvernoteConnection::ErrorCode errorCode, const QString &errorMessage, const evernote::edam::Note &note);
210
211
212=== modified file 'src/libqtevernote/notesstore.cpp'
213--- src/libqtevernote/notesstore.cpp 2015-06-21 16:28:58 +0000
214+++ src/libqtevernote/notesstore.cpp 2015-09-08 16:22:25 +0000
215@@ -878,13 +878,17 @@
216 qCWarning(dcSync) << "can't find note for this update... ignoring...";
217 return;
218 }
219+ if (note->updateSequenceNumber() > result.updateSequenceNum) {
220+ qCWarning(dcSync) << "Local update sequence number higher than remote. Local:" << note->updateSequenceNumber() << "remote:" << result.updateSequenceNum;
221+ return;
222+ }
223
224 QModelIndex noteIndex = index(m_notes.indexOf(note));
225 QVector<int> roles;
226
227 handleUserError(errorCode);
228 if (errorCode != EvernoteConnection::ErrorCodeNoError) {
229- qWarning(dcSync) << "Fetch note job failed:" << errorMessage;
230+ qCWarning(dcSync) << "Fetch note job failed:" << errorMessage;
231 note->setLoading(false);
232 roles << RoleLoading;
233 note->setSyncError(true);
234@@ -1389,11 +1393,11 @@
235 // This note hasn't been created on the server yet... try that first
236 CreateNoteJob *job = new CreateNoteJob(note, this);
237 connect(job, &CreateNoteJob::jobDone, this, &NotesStore::createNoteJobDone);
238- EvernoteConnection::instance()->enqueue(job);
239+ EvernoteConnection::instance()->enqueueWrite(job);
240 } else {
241 SaveNoteJob *job = new SaveNoteJob(note, this);
242 connect(job, &SaveNoteJob::jobDone, this, &NotesStore::saveNoteJobDone);
243- EvernoteConnection::instance()->enqueue(job);
244+ EvernoteConnection::instance()->enqueueWrite(job);
245 }
246 }
247
248@@ -1415,24 +1419,19 @@
249
250 int idx = m_notes.indexOf(note);
251 note->setLoading(false);
252+ QModelIndex noteIndex = index(idx);
253
254 handleUserError(errorCode);
255 if (errorCode != EvernoteConnection::ErrorCodeNoError) {
256 qCWarning(dcSync) << "Unhandled error saving note:" << errorCode << "Message:" << errorMessage;
257 note->setSyncError(true);
258- emit dataChanged(index(idx), index(idx), QVector<int>() << RoleLoading << RoleSyncError);
259+ emit dataChanged(noteIndex, noteIndex, QVector<int>() << RoleLoading << RoleSyncError);
260 return;
261 }
262
263- note->setUpdateSequenceNumber(result.updateSequenceNum);
264 note->setLastSyncedSequenceNumber(result.updateSequenceNum);
265- note->setTitle(QString::fromStdString(result.title));
266- note->setNotebookGuid(QString::fromStdString(result.notebookGuid));
267- note->setUpdated(QDateTime::fromMSecsSinceEpoch(result.updated));
268-
269 syncToCacheFile(note);
270
271- QModelIndex noteIndex = index(m_notes.indexOf(note));
272 emit dataChanged(noteIndex, noteIndex);
273 emit noteChanged(note->guid(), note->notebookGuid());
274 }

Subscribers

People subscribed via source and target branches