From 9497dd286d8abe371adfaefc930e3b373c4205e7 Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 10 Mar 2016 16:12:10 +0100 Subject: [PATCH] expand TransactionGuard FAQ --- .../openapi/application/TransactionGuard.java | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/platform/core-api/src/com/intellij/openapi/application/TransactionGuard.java b/platform/core-api/src/com/intellij/openapi/application/TransactionGuard.java index bef6ce81aabd..890f9289420d 100644 --- a/platform/core-api/src/com/intellij/openapi/application/TransactionGuard.java +++ b/platform/core-api/src/com/intellij/openapi/application/TransactionGuard.java @@ -43,6 +43,25 @@ import org.jetbrains.annotations.NotNull; * *

FAQ

* + * Q: How large/long should transactions be? + * A: As short as possible, but not shorter. Take them for minimal period of time that you need the model you're working with + * to be consistent. If your action doesn't require any user interaction, the whole action can be wrapped inside + * a transaction (see {@link WrapInTransaction}). If the action only displays a dialog (e.g. Settings) and does nothing else, + * it probably shouldn't take a transaction for all the dialog showing time. + * Actions inside the dialog should care of transactions themselves.

+ * + * The most complicated case is when the action both displays modal dialogs and performs modifications. The only case when those dialogs + * should be shown under a transaction is when the mere reason of their showing lies somewhere in PSI/VFS/project model, and the are not + * prepared to foreign code affecting the state of things at the moment of showing. For example, dialogs asking for making files writable + * are shown only because VFS indicates the file is read-only. So they wouldn't make sense if they allowed modifications to that file + * while they're shown. Their clients are not prepared to such changes either. So such dialogs should be shown under the same transaction, + * as the following meaningful modifications performed by the action. Most refactoring dialogs are similar and refactoring actions should + * take transactions for the whole refactoring process, with all the dialogs inside.

+ * + * Having said all that, it's still advisable that the transactions be as short as possible and preferably exclude any modal dialogs + * for which transaction-ness is not critical. So a better overall strategy would be to either make the dialogs non-modal, + * or at least make them and the code that shows them prepared for possible model changes while the dialog is shown. + * * Q: I've got "Write access is allowed from model transactions only" exception, what do I do?
* A: Add a transaction somewhere into the call stack, to the outermost callee where having read/write model consistency is needed. * If it's a user action, transaction should be synchronous (see {@link #startSynchronousTransaction(TransactionKind)}. For AnAction @@ -89,7 +108,7 @@ public abstract class TransactionGuard { * The code will be run on Swing thread immediately or after all other queued transactions (if any) have been completed.

* * For more advanced version, see {@link #submitMergeableTransaction(TransactionKind, Runnable)}. - * Transactions submitted via this method use {@link TransactionKind#NO_MERGE} kind. + * Transactions submitted via this method use {@link TransactionKind#ANY_CHANGE} kind. * * @param transaction code to execute inside a transaction. */ @@ -150,7 +169,7 @@ public abstract class TransactionGuard { * and executes the provided code immediately. Otherwise * adds the runnable to a queue. When all transactions scheduled before this one are finished, executes the given * runnable under a transaction. - * @param kind a kind object to enable transaction merging or {@link TransactionKind#NO_MERGE}, if no merging is required. + * @param kind a "kind" object for transaction merging * @param transaction code to execute inside a transaction. */ public abstract void submitMergeableTransaction(@NotNull TransactionKind kind, @NotNull Runnable transaction);