storage/public/mozStorageHelper.h

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:736a3eafbf84
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #ifndef MOZSTORAGEHELPER_H
7 #define MOZSTORAGEHELPER_H
8
9 #include "nsAutoPtr.h"
10
11 #include "mozIStorageAsyncConnection.h"
12 #include "mozIStorageConnection.h"
13 #include "mozIStorageStatement.h"
14 #include "nsError.h"
15
16 /**
17 * This class wraps a transaction inside a given C++ scope, guaranteeing that
18 * the transaction will be completed even if you have an exception or
19 * return early.
20 *
21 * aCommitOnComplete controls whether the transaction is committed or rolled
22 * back when it goes out of scope. A common use is to create an instance with
23 * commitOnComplete = FALSE (rollback), then call Commit on this object manually
24 * when your function completes successfully.
25 *
26 * Note that nested transactions are not supported by sqlite, so if a transaction
27 * is already in progress, this object does nothing. Note that in this case,
28 * you may not get the transaction type you ask for, and you won't be able
29 * to rollback.
30 *
31 * Note: This class is templatized to be also usable with internal data
32 * structures. External users of this class should generally use
33 * |mozStorageTransaction| instead.
34 */
35 template<typename T, typename U>
36 class mozStorageTransactionBase
37 {
38 public:
39 mozStorageTransactionBase(T* aConnection,
40 bool aCommitOnComplete,
41 int32_t aType = mozIStorageConnection::TRANSACTION_DEFERRED)
42 : mConnection(aConnection),
43 mHasTransaction(false),
44 mCommitOnComplete(aCommitOnComplete),
45 mCompleted(false)
46 {
47 // We won't try to get a transaction if one is already in progress.
48 if (mConnection)
49 mHasTransaction = NS_SUCCEEDED(mConnection->BeginTransactionAs(aType));
50 }
51 ~mozStorageTransactionBase()
52 {
53 if (mConnection && mHasTransaction && ! mCompleted) {
54 if (mCommitOnComplete)
55 mConnection->CommitTransaction();
56 else
57 mConnection->RollbackTransaction();
58 }
59 }
60
61 /**
62 * Commits the transaction if one is in progress. If one is not in progress,
63 * this is a NOP since the actual owner of the transaction outside of our
64 * scope is in charge of finally comitting or rolling back the transaction.
65 */
66 nsresult Commit()
67 {
68 if (!mConnection || mCompleted)
69 return NS_OK; // no connection, or already done
70 mCompleted = true;
71 if (! mHasTransaction)
72 return NS_OK; // transaction not ours, ignore
73 nsresult rv = mConnection->CommitTransaction();
74 if (NS_SUCCEEDED(rv))
75 mHasTransaction = false;
76
77 return rv;
78 }
79
80 /**
81 * Rolls back the transaction in progress. You should only call this function
82 * if this object has a real transaction (HasTransaction() = true) because
83 * otherwise, there is no transaction to roll back.
84 */
85 nsresult Rollback()
86 {
87 if (!mConnection || mCompleted)
88 return NS_OK; // no connection, or already done
89 mCompleted = true;
90 if (! mHasTransaction)
91 return NS_ERROR_FAILURE;
92
93 // It is possible that a rollback will return busy, so we busy wait...
94 nsresult rv = NS_OK;
95 do {
96 rv = mConnection->RollbackTransaction();
97 if (rv == NS_ERROR_STORAGE_BUSY)
98 (void)PR_Sleep(PR_INTERVAL_NO_WAIT);
99 } while (rv == NS_ERROR_STORAGE_BUSY);
100
101 if (NS_SUCCEEDED(rv))
102 mHasTransaction = false;
103
104 return rv;
105 }
106
107 /**
108 * Returns whether this object wraps a real transaction. False means that
109 * this object doesn't do anything because there was already a transaction in
110 * progress when it was created.
111 */
112 bool HasTransaction()
113 {
114 return mHasTransaction;
115 }
116
117 /**
118 * This sets the default action (commit or rollback) when this object goes
119 * out of scope.
120 */
121 void SetDefaultAction(bool aCommitOnComplete)
122 {
123 mCommitOnComplete = aCommitOnComplete;
124 }
125
126 protected:
127 U mConnection;
128 bool mHasTransaction;
129 bool mCommitOnComplete;
130 bool mCompleted;
131 };
132
133 /**
134 * An instance of the mozStorageTransaction<> family dedicated
135 * to |mozIStorageConnection|.
136 */
137 typedef mozStorageTransactionBase<mozIStorageConnection,
138 nsCOMPtr<mozIStorageConnection> >
139 mozStorageTransaction;
140
141
142
143 /**
144 * This class wraps a statement so that it is guaraneed to be reset when
145 * this object goes out of scope.
146 *
147 * Note that this always just resets the statement. If the statement doesn't
148 * need resetting, the reset operation is inexpensive.
149 */
150 class MOZ_STACK_CLASS mozStorageStatementScoper
151 {
152 public:
153 mozStorageStatementScoper(mozIStorageStatement* aStatement)
154 : mStatement(aStatement)
155 {
156 }
157 ~mozStorageStatementScoper()
158 {
159 if (mStatement)
160 mStatement->Reset();
161 }
162
163 /**
164 * Call this to make the statement not reset. You might do this if you know
165 * that the statement has been reset.
166 */
167 void Abandon()
168 {
169 mStatement = nullptr;
170 }
171
172 protected:
173 nsCOMPtr<mozIStorageStatement> mStatement;
174 };
175
176 // Use this to make queries uniquely identifiable in telemetry
177 // statistics, especially PRAGMAs. We don't include __LINE__ so that
178 // queries are stable in the face of source code changes.
179 #define MOZ_STORAGE_UNIQUIFY_QUERY_STR "/* " __FILE__ " */ "
180
181 #endif /* MOZSTORAGEHELPER_H */

mercurial