From 5f5d7ef249243fc401be691a5343b91aa4616772 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 25 Oct 2013 11:19:11 +2000 Subject: [PATCH] [PATCH v2 11/11] emacs: Fix search tagging races --- ef/8761481f353d3728c3bd3f7f2b8636277d349e | 218 ++++++++++++++++++++++ 1 file changed, 218 insertions(+) create mode 100644 ef/8761481f353d3728c3bd3f7f2b8636277d349e diff --git a/ef/8761481f353d3728c3bd3f7f2b8636277d349e b/ef/8761481f353d3728c3bd3f7f2b8636277d349e new file mode 100644 index 000000000..3af1cf628 --- /dev/null +++ b/ef/8761481f353d3728c3bd3f7f2b8636277d349e @@ -0,0 +1,218 @@ +Return-Path: +X-Original-To: notmuch@notmuchmail.org +Delivered-To: notmuch@notmuchmail.org +Received: from localhost (localhost [127.0.0.1]) + by olra.theworths.org (Postfix) with ESMTP id 37F54429E45 + for ; Thu, 24 Oct 2013 08:19:50 -0700 (PDT) +X-Virus-Scanned: Debian amavisd-new at olra.theworths.org +X-Spam-Flag: NO +X-Spam-Score: -0.7 +X-Spam-Level: +X-Spam-Status: No, score=-0.7 tagged_above=-999 required=5 + tests=[RCVD_IN_DNSWL_LOW=-0.7] autolearn=disabled +Received: from olra.theworths.org ([127.0.0.1]) + by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024) + with ESMTP id Sa26Z-GJxz2p for ; + Thu, 24 Oct 2013 08:19:43 -0700 (PDT) +Received: from dmz-mailsec-scanner-5.mit.edu (dmz-mailsec-scanner-5.mit.edu + [18.7.68.34]) + by olra.theworths.org (Postfix) with ESMTP id 323C4429E4E + for ; Thu, 24 Oct 2013 08:19:25 -0700 (PDT) +X-AuditID: 12074422-b7f5a8e000000a34-f4-52693a7cc45b +Received: from mailhub-auth-3.mit.edu ( [18.9.21.43]) + by dmz-mailsec-scanner-5.mit.edu (Symantec Messaging Gateway) with SMTP + id 6F.56.02612.C7A39625; Thu, 24 Oct 2013 11:19:24 -0400 (EDT) +Received: from outgoing.mit.edu (outgoing-auth-1.mit.edu [18.9.28.11]) + by mailhub-auth-3.mit.edu (8.13.8/8.9.2) with ESMTP id r9OFJJha030444; + Thu, 24 Oct 2013 11:19:20 -0400 +Received: from drake.dyndns.org + (216-15-114-40.c3-0.arl-ubr1.sbo-arl.ma.cable.rcn.com + [216.15.114.40]) (authenticated bits=0) + (User authenticated as amdragon@ATHENA.MIT.EDU) + by outgoing.mit.edu (8.13.8/8.12.4) with ESMTP id r9OFJDDw012929 + (version=TLSv1/SSLv3 cipher=AES256-SHA bits=256 verify=NOT); + Thu, 24 Oct 2013 11:19:19 -0400 +Received: from amthrax by drake.dyndns.org with local (Exim 4.77) + (envelope-from ) + id 1VZMgq-0006eB-U8; Thu, 24 Oct 2013 11:19:12 -0400 +From: Austin Clements +To: notmuch@notmuchmail.org +Subject: [PATCH v2 11/11] emacs: Fix search tagging races +Date: Thu, 24 Oct 2013 11:19:11 -0400 +Message-Id: <1382627951-25252-12-git-send-email-amdragon@mit.edu> +X-Mailer: git-send-email 1.8.4.rc3 +In-Reply-To: <1382627951-25252-1-git-send-email-amdragon@mit.edu> +References: <1382627951-25252-1-git-send-email-amdragon@mit.edu> +X-Brightmail-Tracker: + H4sIAAAAAAAAA+NgFjrGIsWRmVeSWpSXmKPExsUixCmqrVtjlRlkcOSztkXTdGeL1XN5LK7f + nMnswOyxc9Zddo9b91+zezxbdYs5gDmKyyYlNSezLLVI3y6BK+PH1GamgouGFdM/trA1MPZr + djFyckgImEgs3dDKCGGLSVy4t56ti5GLQ0hgH6PEulkP2CGcjYwSVzunMkI4d5gkpr7sYYZw + 5jJKnJ78igmkn01AQ2Lb/uVgs0QEpCV23p3NCmIzC0RLHLk8gw3EFhawlDjVs5EFxGYRUJXo + 3/+dGcTmFXCUOPXzFDPEHUoSC09tA+vlBIr/fH0NbKaQgIPEr99nWCYw8i9gZFjFKJuSW6Wb + m5iZU5yarFucnJiXl1qka6qXm1mil5pSuokRFFzsLko7GH8eVDrEKMDBqMTDq/EhPUiINbGs + uDL3EKMkB5OSKO8908wgIb6k/JTKjMTijPii0pzU4kOMEhzMSiK80/SAcrwpiZVVqUX5MClp + DhYlcd5bHPZBQgLpiSWp2ampBalFMFkZDg4lCV5/S6BGwaLU9NSKtMycEoQ0EwcnyHAeoOHp + IDW8xQWJucWZ6RD5U4yKUuK8SSAJAZBERmkeXC8s+l8xigO9IsxbDlLFA0wccN2vgAYzAQ2e + siQNZHBJIkJKqoFRrfKAl6dM0HkmtqSpfd07TU4VVvy1iNghu1sijWnprqz628/eqycs3H3p + jkacf7btT+6kv5aGd2ovWhittdpzX1mHuThs8414dd/rM5Y8uXZNbPe31aH+8199Xsy0SXqJ + 9k2eKIFtn0Kt36flPfaXUQmVkZ42Qa/+YaflN/YM6w2FMx3Wzb2uxFKckWioxVxUnAgA8FCt + ktkCAAA= +X-BeenThere: notmuch@notmuchmail.org +X-Mailman-Version: 2.1.13 +Precedence: list +List-Id: "Use and development of the notmuch mail system." + +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +X-List-Received-Date: Thu, 24 Oct 2013 15:19:50 -0000 + +This fixes races in thread-local and global tagging in notmuch-search +(e.g., "+", "-", "a", "*", etc.). Previously, these would modify tags +of new messages that arrived after the search. Now they only operate +on the messages that were in the threads when the search was +performed. This prevents surprises like archiving messages that +arrived in a thread after the search results were shown. + +This eliminates `notmuch-search-find-thread-id-region(-search)' +because these functions strongly encouraged racy usage. + +This fixes the two broken tests added by the previous patch. +--- + devel/TODO | 5 ----- + emacs/notmuch.el | 40 +++++++++++++++++++++++++++------------- + test/emacs | 4 +--- + 3 files changed, 28 insertions(+), 21 deletions(-) + +diff --git a/devel/TODO b/devel/TODO +index f212483..1cf4089 100644 +--- a/devel/TODO ++++ b/devel/TODO +@@ -14,11 +14,6 @@ sender's name containing ';' which causes emacs to drop a search + result.) This may require removing the outer array from the current + "notmuch search --format=json" results. + +-Fix '*' to work by simply calling '+' or '-' on a region consisting of +-the entire buffer, (this would avoid one race condition---while still +-leaving other race conditions---but could also potentially make '*' a +-very expensive operation). +- + Add a global keybinding table for notmuch, and then view-specific + tables that add to it. + +diff --git a/emacs/notmuch.el b/emacs/notmuch.el +index 496c8ec..fea1a93 100644 +--- a/emacs/notmuch.el ++++ b/emacs/notmuch.el +@@ -485,14 +485,25 @@ If BARE is set then do not prefix with \"thread:\"" + (let ((thread (plist-get (notmuch-search-get-result) :thread))) + (when thread (concat (unless bare "thread:") thread)))) + +-(defun notmuch-search-find-thread-id-region (beg end) +- "Return a list of threads for the current region" +- (mapcar (lambda (thread) (concat "thread:" thread)) +- (notmuch-search-properties-in-region :thread beg end))) +- +-(defun notmuch-search-find-thread-id-region-search (beg end) +- "Return a search string for threads for the current region" +- (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or ")) ++(defun notmuch-search-find-stable-query () ++ "Return the stable queries for the current thread. ++ ++This returns a list (MATCHED-QUERY UNMATCHED-QUERY) for the ++matched and unmatched messages in the current thread." ++ (plist-get (notmuch-search-get-result) :query)) ++ ++(defun notmuch-search-find-stable-query-region (beg end &optional only-matched) ++ "Return the stable query for the current region. ++ ++If ONLY-MATCHED is non-nil, include only matched messages. If it ++is nil, include both matched and unmatched messages." ++ (let ((query-list nil) (all (not only-matched))) ++ (dolist (queries (notmuch-search-properties-in-region :query beg end)) ++ (when (first queries) ++ (push (first queries) query-list)) ++ (when (and all (second queries)) ++ (push (second queries) query-list))) ++ (concat "(" (mapconcat 'identity query-list ") or (") ")"))) + + (defun notmuch-search-find-authors () + "Return the authors for the current thread" +@@ -569,17 +580,20 @@ Returns (TAG-CHANGES REGION-BEGIN REGION-END)." + (notmuch-search-get-tags-region beg end) prompt initial-input) + region))) + +-(defun notmuch-search-tag (tag-changes &optional beg end) ++(defun notmuch-search-tag (tag-changes &optional beg end only-matched) + "Change tags for the currently selected thread or region. + + See `notmuch-tag' for information on the format of TAG-CHANGES. + When called interactively, this uses the region if the region is + active. When called directly, BEG and END provide the region. + If these are nil or not provided, this applies to the thread at +-point." ++point. ++ ++If ONLY-MATCHED is non-nil, only tag matched messages." + (interactive (notmuch-search-interactive-tag-changes)) + (unless (and beg end) (setq beg (point) end (point))) +- (let ((search-string (notmuch-search-find-thread-id-region-search beg end))) ++ (let ((search-string (notmuch-search-find-stable-query-region ++ beg end only-matched))) + (notmuch-tag search-string tag-changes) + (notmuch-search-foreach-result beg end + (lambda (pos) +@@ -847,7 +861,7 @@ See `notmuch-tag' for information on the format of TAG-CHANGES." + (interactive + (list (notmuch-read-tag-changes + (notmuch-search-get-tags-region (point-min) (point-max)) "Tag all"))) +- (notmuch-tag notmuch-search-query-string tag-changes)) ++ (notmuch-search-tag tag-changes (point-min) (point-max) t)) + + (defun notmuch-search-buffer-title (query) + "Returns the title for a buffer with notmuch search results." +@@ -951,7 +965,7 @@ the configured default sort order." + (save-excursion + (let ((proc (notmuch-start-notmuch + "notmuch-search" buffer #'notmuch-search-process-sentinel +- "search" "--format=sexp" "--format-version=1" ++ "search" "--format=sexp" "--format-version=2" + (if oldest-first + "--sort=oldest-first" + "--sort=newest-first") +diff --git a/test/emacs b/test/emacs +index 7503e96..3b3b14d 100755 +--- a/test/emacs ++++ b/test/emacs +@@ -889,7 +889,7 @@ $PWD/notmuch_fail exited with status 1 (see *Notmuch errors* for more details) + --- + [XXX] + $PWD/notmuch_fail exited with status 1 +-command: $PWD/notmuch_fail search --format\=sexp --format-version\=1 --sort\=newest-first tag\:inbox ++command: $PWD/notmuch_fail search --format\=sexp --format-version\=2 --sort\=newest-first tag\:inbox + exit status: 1" + + test_begin_subtest "Search handles subprocess warnings" +@@ -923,7 +923,6 @@ This is a warning + This is another warning" + + test_begin_subtest "Search thread tag operations are race-free" +-test_subtest_known_broken + add_message '[subject]="Search race test"' + gen_msg_id_1=$gen_msg_id + generate_message '[in-reply-to]="<'$gen_msg_id_1'>"' \ +@@ -937,7 +936,6 @@ output=$(notmuch search --output=messages 'tag:search-thread-race-tag') + test_expect_equal "$output" "id:$gen_msg_id_1" + + test_begin_subtest "Search global tag operations are race-free" +-test_subtest_known_broken + generate_message '[in-reply-to]="<'$gen_msg_id_1'>"' \ + '[references]="<'$gen_msg_id_1'>"' \ + '[subject]="Re: Search race test"' +-- +1.8.4.rc3 + -- 2.26.2