|
1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 #include "UT_STD.H" |
|
17 |
|
18 // Class RDbTransaction::CNotifier |
|
19 |
|
20 NONSHARABLE_CLASS(RDbTransaction::CNotifier) : public CDbNotifier |
|
21 { |
|
22 public: |
|
23 inline CNotifier( RDbTransaction& aTransaction ); |
|
24 ~CNotifier(); |
|
25 // |
|
26 // void Event( RDbNotifier::TEvent aEvent ); |
|
27 private: |
|
28 // void Complete( TInt aStatus ); |
|
29 // from CDbNotifier |
|
30 // void Notify( TType aEvent, TRequestStatus& aStatus ); |
|
31 void Cancel(); |
|
32 private: |
|
33 RDbTransaction* iTransaction; |
|
34 // TRequestStatus* iStatus; |
|
35 TInt iPending; |
|
36 }; |
|
37 |
|
38 inline RDbTransaction::CNotifier::CNotifier( RDbTransaction& aTransaction ) |
|
39 : iTransaction( &aTransaction ) |
|
40 {} |
|
41 |
|
42 RDbTransaction::CNotifier::~CNotifier() |
|
43 // |
|
44 // Cancel any outstanding request and extract from the transaction |
|
45 // |
|
46 { |
|
47 Cancel(); |
|
48 if ( iTransaction ) |
|
49 { |
|
50 __ASSERT( iTransaction->iNotifier == this ); |
|
51 iTransaction->iNotifier = 0; |
|
52 } |
|
53 } |
|
54 |
|
55 //void RDbTransaction::CNotifier::Complete( TInt aStatus ) |
|
56 // { |
|
57 // if ( iStatus ) |
|
58 // { |
|
59 // iPending = 0; |
|
60 // User::RequestComplete( iStatus, aStatus ); |
|
61 // } |
|
62 // } |
|
63 |
|
64 //void RDbTransaction::CNotifier::Notify( CDbNotifier::TType aType, TRequestStatus& aStatus ) |
|
65 //// |
|
66 //// Request for future notification. If the database is closed complete immediately |
|
67 //// |
|
68 // { |
|
69 // __ASSERT( !iStatus ); |
|
70 // __ASSERT( iPending >= 0 ); |
|
71 // iStatus = &aStatus; |
|
72 // if ( iPending > RDbNotifier::EUnlock ) |
|
73 // Complete( iPending ); |
|
74 // else if ( !iTransaction ) |
|
75 // Complete( RDbNotifier::EClose ); |
|
76 // else |
|
77 // { |
|
78 // iPending = aType; |
|
79 // aStatus = KRequestPending; |
|
80 // } |
|
81 // } |
|
82 |
|
83 void RDbTransaction::CNotifier::Cancel() |
|
84 { |
|
85 // Complete( KErrCancel ); |
|
86 } |
|
87 |
|
88 //void RDbTransaction::CNotifier::Event( RDbNotifier::TEvent aEvent ) |
|
89 // { |
|
90 // if ( aEvent == RDbNotifier::EClose ) |
|
91 // iTransaction = 0; |
|
92 // if ( iStatus ) |
|
93 // { |
|
94 // __ASSERT( iPending < 0 ); |
|
95 // if (aEvent == RDbNotifier::EUnlock && iPending == CDbNotifier::EChange ) |
|
96 // ; // not interested in unlock events |
|
97 // else |
|
98 // Complete( aEvent ); |
|
99 // } |
|
100 // else |
|
101 // { |
|
102 // __ASSERT( iPending >= 0 ); |
|
103 // if ( aEvent > iPending ) |
|
104 // iPending = aEvent; // save the event |
|
105 // } |
|
106 // } |
|
107 |
|
108 |
|
109 // Class RDbTransaction |
|
110 |
|
111 #ifdef _ASSERTIONS |
|
112 |
|
113 //void RDbTransaction::_Invariant() const |
|
114 //// |
|
115 //// Invariance test |
|
116 //// |
|
117 // { |
|
118 // if ( iLockCount == 0 ) |
|
119 // { // nothing must be happening in this state |
|
120 // __ASSERT( iLockState == EDbReadLock ); |
|
121 // __ASSERT( iAction == EDbReadLock ); |
|
122 // __ASSERT( iUpdaters == 0 ); |
|
123 // return; |
|
124 // } |
|
125 // switch ( iLockState & EState ) |
|
126 // { |
|
127 // default: |
|
128 // __ASSERT( 0 ); |
|
129 // case EDbReadLock: |
|
130 // { |
|
131 // __ASSERT( iAction == EDbReadLock ); |
|
132 // __ASSERT( iLockCount > 0 ); // someone must have a lock |
|
133 // __ASSERT( iLockCount <= iMaxLock ); |
|
134 // __ASSERT( iUpdaters == 0 ); |
|
135 // __ASSERT( iPrimary.iState != 0 ); |
|
136 // for (TInt ii = iLockCount - 1; --ii >= 0; ) |
|
137 // __ASSERT( iSharers[ii].iState != 0 ); |
|
138 // } |
|
139 // break; |
|
140 // case EDbCompactLock: // not allowed in user-transactions |
|
141 // case EDbRecoveryLock: |
|
142 // __ASSERT( iAction == iLockState ); |
|
143 // __ASSERT( iLockCount == 1 ); // exactly one lock allowed |
|
144 // __ASSERT( iUpdaters == 0 ); |
|
145 // __ASSERT( iPrimary.iState == 0 ); |
|
146 // break; |
|
147 // case EDbXReadLock: // intention to write. No updates but exclusive |
|
148 // __ASSERT( iLockCount == 1 ); // exactly one lock allowed |
|
149 // switch ( iAction ) |
|
150 // { |
|
151 // default: |
|
152 // __ASSERT( 0 ); |
|
153 // case EDbReadLock: // must be in a transaction: cannot commit a write/schema mod when releasing a read lock |
|
154 // __ASSERT( iUpdaters == 0 ); |
|
155 // __ASSERT( iPrimary.iState & static_cast<TUint>( ETransactionLock ) ); |
|
156 // break; |
|
157 // case EDbWriteLock: |
|
158 // __ASSERT( iUpdaters > 0 ); |
|
159 // break; |
|
160 // } |
|
161 // break; |
|
162 // case EDbWriteLock: |
|
163 // case EDbSchemaLock: |
|
164 // __ASSERT( iLockCount == 1 ); // exactly one lock allowed |
|
165 // switch ( iAction ) |
|
166 // { |
|
167 // default: |
|
168 // __ASSERT( 0 ); |
|
169 // case EDbReadLock: // must be in a transaction: cannot commit a write/schema mod when releasing a read lock |
|
170 // __ASSERT( iUpdaters == 0 ); |
|
171 // __ASSERT( iPrimary.iState & static_cast<TUint>( ETransactionLock ) ); |
|
172 // break; |
|
173 // case EDbWriteLock: |
|
174 // __ASSERT( iUpdaters > 0 ); |
|
175 // __ASSERT( ( iLockState & EState ) == EDbWriteLock || ( iPrimary.iState & static_cast<TUint>( ETransactionLock ) ) ); |
|
176 // break; |
|
177 // case EDbSchemaLock: |
|
178 // __ASSERT( ( iLockState & EState ) == EDbSchemaLock ); |
|
179 // __ASSERT( iUpdaters == 0 ); |
|
180 // break; |
|
181 // } |
|
182 // break; |
|
183 // } |
|
184 // } |
|
185 |
|
186 //template <class T> struct _InvariantFunc |
|
187 // { |
|
188 // static void Invariant( TAny* aPtr ) { ( (const T*)aPtr )->_Invariant(); } |
|
189 // }; |
|
190 // |
|
191 //template <class T> inline TCleanupOperation _InvariantFunction( T* ) |
|
192 // { return _InvariantFunc<T>::Invariant; } |
|
193 // |
|
194 //struct _Invariant |
|
195 // { |
|
196 // inline _Invariant( TCleanupOperation aOp, TAny* aPtr ) |
|
197 // : iOp( aOp ), iPtr( aPtr ) |
|
198 // { aOp( aPtr ); } |
|
199 // inline ~_Invariant() |
|
200 // { iOp( iPtr ); } |
|
201 //private: |
|
202 // TCleanupOperation iOp; |
|
203 // TAny* iPtr; |
|
204 // }; |
|
205 |
|
206 #ifndef __LEAVE_EQUALS_THROW |
|
207 //struct _InvariantL |
|
208 // { |
|
209 // inline _InvariantL( TCleanupOperation aOp, TAny* aPtr ) |
|
210 // { aOp( aPtr ); CleanupStack::PushL( TCleanupItem( aOp, aPtr ) ); } |
|
211 // inline ~_InvariantL() |
|
212 // { CleanupStack::PopAndDestroy(); } |
|
213 // }; |
|
214 #endif //__LEAVE_EQUALS_THROW__ |
|
215 |
|
216 //#define __INVARIANT struct _Invariant _invariant( _InvariantFunction( this ), this ); |
|
217 |
|
218 //#ifdef __LEAVE_EQUALS_THROW__ |
|
219 // #define __INVARIANT_L __INVARIANT |
|
220 //#else |
|
221 // #define __INVARIANT_L struct _InvariantL _invariant( _InvariantFunction( this ), this ); |
|
222 //#endif //__LEAVE_EQUALS_THROW__ |
|
223 |
|
224 #define __INVARIANT ( (void)0 ) |
|
225 #define __INVARIANT_L ( (void)0 ) |
|
226 #else // _ASSERTIONS |
|
227 |
|
228 #define __INVARIANT ( (void)0 ) |
|
229 #define __INVARIANT_L ( (void)0 ) |
|
230 |
|
231 #endif // _ASSERTIONS |
|
232 |
|
233 inline TDbLockType RDbTransaction::LockState() const |
|
234 { return TDbLockType( iLockState & EState ); } |
|
235 |
|
236 void RDbTransaction::Close() |
|
237 { |
|
238 __ASSERT( !IsLocked() ); |
|
239 User::Free( iSharers ); |
|
240 // Event( RDbNotifier::EClose ); |
|
241 } |
|
242 |
|
243 void RDbTransaction::DoCommitL() |
|
244 // |
|
245 // Commit any changes |
|
246 // |
|
247 { |
|
248 __ASSERT_ALWAYS( ( iPrimary.iState & ~ETransactionLock ) == 0, Panic( EDbStreamsPendingOnCommit ) ); |
|
249 iLockState |= EFailed; |
|
250 Database().FlushL( LockState() ); |
|
251 Database().SynchL( LockState() ); |
|
252 Unlock( RDbNotifier::ECommit ); |
|
253 } |
|
254 |
|
255 void RDbTransaction::DoRollback() |
|
256 // |
|
257 // Rollback any changes |
|
258 // |
|
259 { |
|
260 __ASSERT_ALWAYS( ( iPrimary.iState & ~ETransactionLock ) == 0, Panic( EDbStreamsPendingOnRollback ) ); |
|
261 Database().Revert( LockState() ); |
|
262 Database().Abandon( LockState() ); |
|
263 if ( LockState() >= EDbWriteLock ) |
|
264 ++iRollback; |
|
265 Unlock( RDbNotifier::ERollback ); |
|
266 } |
|
267 |
|
268 // explicit transactions |
|
269 |
|
270 void RDbTransaction::BeginL( const CDbObject& aObject ) |
|
271 // |
|
272 // begin a user transaction. This first gains a shared read-lock |
|
273 // |
|
274 { |
|
275 __INVARIANT_L; |
|
276 __ASSERT_ALWAYS( GetLock( aObject ) == 0, Panic( EDbBeginNestedTransaction ) ); |
|
277 ReadyL(); |
|
278 PrepareSLockL( aObject, TUint( ETransactionLock ) ); |
|
279 __ASSERT( iAction == EDbReadLock ); |
|
280 __ASSERT( iLockState == EDbReadLock ); |
|
281 ++iLockCount; |
|
282 } |
|
283 |
|
284 void RDbTransaction::CommitL( const CDbObject& aObject ) |
|
285 // |
|
286 // Commit a user transaction and release the lock |
|
287 // All updates must be complete for a write-lock |
|
288 // |
|
289 { |
|
290 __INVARIANT_L; |
|
291 __ASSERT_ALWAYS( InTransaction( aObject ), Panic( EDbNoCurrentTransaction ) ); |
|
292 ReadyL(); |
|
293 if ( iLockCount > 1 ) |
|
294 { |
|
295 TLock* lock = GetLock( aObject ); |
|
296 __ASSERT( lock ); |
|
297 __ASSERT_ALWAYS( lock->iState == static_cast<TUint>( ETransactionLock ), Panic( EDbStreamsPendingOnCommit ) ); |
|
298 Unlock( *lock ); |
|
299 } |
|
300 else |
|
301 { |
|
302 __ASSERT_ALWAYS( iAction == EDbReadLock, Panic( EDbUpdatesPendingOnCommit ) ); |
|
303 DoCommitL(); |
|
304 } |
|
305 } |
|
306 |
|
307 void RDbTransaction::Rollback( const CDbObject& aObject ) |
|
308 // |
|
309 // Rollback a user transaction and release the lock |
|
310 // All updates must be complete/aborted for a write-lock |
|
311 // |
|
312 { |
|
313 __INVARIANT; |
|
314 __ASSERT_ALWAYS( InTransaction( aObject ), Panic( EDbNoCurrentTransaction ) ); |
|
315 if ( iLockCount > 1 ) |
|
316 { |
|
317 TLock* lock = GetLock( aObject ); |
|
318 __ASSERT( lock ); |
|
319 __ASSERT_ALWAYS( lock->iState == static_cast<TUint>( ETransactionLock ), Panic( EDbStreamsPendingOnRollback ) ); |
|
320 Unlock( *lock ); |
|
321 } |
|
322 else |
|
323 { |
|
324 __ASSERT_ALWAYS( iAction == EDbReadLock, Panic( EDbUpdatesPendingOnRollback ) ); |
|
325 DoRollback(); |
|
326 } |
|
327 } |
|
328 |
|
329 void RDbTransaction::PrepareSLockL( const CDbObject& aObject, TUint aInitState ) |
|
330 // |
|
331 // prepare to acquire a shared read lock |
|
332 // if any holder has an exclusive lock this fails |
|
333 // |
|
334 { |
|
335 __ASSERT( GetLock( aObject ) == 0 ); // cannot get a 2nd shared lock |
|
336 // |
|
337 THolder h = aObject.Context(); |
|
338 if ( iLockCount == 0 ) |
|
339 { |
|
340 iPrimary.iHolder = h; // first lock, no other checks required |
|
341 iPrimary.iState = aInitState; |
|
342 } |
|
343 else if ( iLockState != EDbReadLock ) |
|
344 __LEAVE( KErrLocked ); |
|
345 else |
|
346 { // allocate a Sharers-slot |
|
347 TLock* share = iSharers; |
|
348 if ( iLockCount == iMaxLock ) |
|
349 { |
|
350 TInt newsize = iMaxLock + ELockListGranularity; |
|
351 if ( newsize > EMaxLock ) |
|
352 { |
|
353 __LEAVE( KErrLocked ); |
|
354 return; |
|
355 } |
|
356 iSharers = share = ( TLock* )User::ReAllocL( share, ( newsize - 1 ) * sizeof( TLock ) ); |
|
357 iMaxLock = TUint8( newsize ); |
|
358 } |
|
359 share += iLockCount - 1; |
|
360 share->iHolder = h; |
|
361 share->iState = aInitState; |
|
362 } |
|
363 } |
|
364 |
|
365 void RDbTransaction::PrepareXLockL( const CDbObject& aObject ) |
|
366 // |
|
367 // prepare to acquire an exclusive lock |
|
368 // if any other holder has a lock this fails |
|
369 // |
|
370 { |
|
371 THolder h = aObject.Context(); |
|
372 switch ( iLockCount ) |
|
373 { |
|
374 case 0: // no other holders, acquire the lock |
|
375 iPrimary.iHolder = h; |
|
376 iPrimary.iState = 0; // this is not a transaction lock |
|
377 break; |
|
378 case 1: // check we are the single Lock holder |
|
379 if (iPrimary.iHolder != h) |
|
380 __LEAVE( KErrLocked ); |
|
381 break; |
|
382 default: // cannot get XLock |
|
383 __LEAVE( KErrLocked ); |
|
384 break; |
|
385 } |
|
386 } |
|
387 |
|
388 void RDbTransaction::Unlock( RDbNotifier::TEvent aEvent ) |
|
389 // |
|
390 // Remove the last lock and signal an event to the Notifier |
|
391 // |
|
392 { |
|
393 __ASSERT( iLockCount == 1 ); |
|
394 __ASSERT( ( iPrimary.iState & ~ETransactionLock ) == 0 ); |
|
395 TDbLockType ls = LockState(); |
|
396 Event( ls == EDbReadLock || ls == EDbXReadLock ? RDbNotifier::EUnlock : aEvent ); |
|
397 iLockCount = 0; |
|
398 iAction = iLockState = EDbReadLock; |
|
399 iUpdaters = 0; |
|
400 Database().CheckIdle(); |
|
401 } |
|
402 |
|
403 void RDbTransaction::Unlock( RDbTransaction::TLock& aLock ) |
|
404 // |
|
405 // Remove a shared lock holder from the list |
|
406 // |
|
407 { |
|
408 __ASSERT( iLockCount > 1 ); |
|
409 __ASSERT( LockState() == EDbReadLock ); |
|
410 __ASSERT( ( aLock.iState & ~ETransactionLock ) == 0 ); |
|
411 aLock = iSharers[--iLockCount - 1]; |
|
412 } |
|
413 |
|
414 RDbTransaction::TLock* RDbTransaction::GetLock( const CDbObject& aObject ) |
|
415 // |
|
416 // Test if aObject holds any lock, and return it |
|
417 // |
|
418 { |
|
419 const THolder h = aObject.Context(); |
|
420 TInt lc = iLockCount; |
|
421 if ( --lc >= 0 ) |
|
422 { |
|
423 if ( iPrimary.iHolder == h ) |
|
424 return &iPrimary; |
|
425 if ( lc > 0 ) |
|
426 { |
|
427 TLock* const base = iSharers; |
|
428 TLock* l = base + lc; |
|
429 do { |
|
430 if ( ( --l )->iHolder == h ) |
|
431 return l; |
|
432 } while ( l > base ); |
|
433 } |
|
434 } |
|
435 return 0; |
|
436 } |
|
437 |
|
438 TBool RDbTransaction::InTransaction( const CDbObject& aObject ) |
|
439 // |
|
440 // Test if aObject holds a non-auto transaction |
|
441 // |
|
442 { |
|
443 __INVARIANT; |
|
444 TLock* lock = GetLock( aObject ); |
|
445 return lock ? lock->iState & static_cast<TUint>( ETransactionLock ) : 0; |
|
446 } |
|
447 |
|
448 void RDbTransaction::ReadPrepareL( const CDbObject& aObject ) |
|
449 // |
|
450 // Check that aObject can gain a shared read lock and allocate required resources |
|
451 // |
|
452 { |
|
453 __INVARIANT_L; |
|
454 if ( GetLock( aObject ) == 0 ) |
|
455 PrepareSLockL( aObject, 0 ); // prepare a S-Lock for the read |
|
456 else if ( iAction == EDbCompactLock ) // Cannot already hold a compaction lock |
|
457 __LEAVE( KErrAccessDenied ); |
|
458 } |
|
459 |
|
460 void RDbTransaction::ReadBegin( const CDbObject& aObject ) |
|
461 // |
|
462 // Take a read-lock: ReadPrepareL(aObject) _must_ already have been called |
|
463 // |
|
464 { |
|
465 __INVARIANT; |
|
466 TLock* lock = GetLock( aObject ); |
|
467 if ( !lock ) |
|
468 { |
|
469 ++iLockCount; |
|
470 lock = GetLock( aObject ); |
|
471 __ASSERT( lock ); |
|
472 } |
|
473 ++lock->iState; |
|
474 } |
|
475 |
|
476 void RDbTransaction::ReadRelease( const CDbObject& aObject ) |
|
477 { |
|
478 __INVARIANT; |
|
479 TLock* lock = GetLock( aObject ); |
|
480 __ASSERT( lock ); |
|
481 __ASSERT( ( lock->iState & ~ETransactionLock ) > 0 ); |
|
482 if ( --lock->iState == 0 ) |
|
483 { // not transaction-lock |
|
484 if ( iLockCount > 1 ) |
|
485 Unlock( *lock ); |
|
486 else if ( iAction == EDbReadLock ) // no other locks to this client |
|
487 Unlock( RDbNotifier::EUnlock ); |
|
488 } |
|
489 } |
|
490 |
|
491 void RDbTransaction::DMLCheckL() |
|
492 // |
|
493 // Check that we can open a new rowset |
|
494 // |
|
495 { |
|
496 __INVARIANT_L; |
|
497 ReadyL(); |
|
498 if ( iAction > EDbCompactLock ) |
|
499 __LEAVE( KErrAccessDenied ); |
|
500 } |
|
501 |
|
502 void RDbTransaction::DMLPrepareL( const CDbObject& aObject ) |
|
503 // |
|
504 // Check that we can do DML, this should be called immediately prior to DMLBegin |
|
505 // |
|
506 { |
|
507 __INVARIANT_L; |
|
508 PrepareXLockL( aObject ); |
|
509 if ( iAction>EDbWriteLock ) |
|
510 __LEAVE( KErrAccessDenied ); |
|
511 } |
|
512 |
|
513 void RDbTransaction::DMLBegin() |
|
514 // |
|
515 // A Rowset begins an update |
|
516 // |
|
517 { |
|
518 __INVARIANT; |
|
519 __ASSERT( iAction == EDbReadLock || iAction == EDbWriteLock ); |
|
520 __ASSERT( ( iLockState & EFailed ) == 0 ); |
|
521 __ASSERT( iLockCount <= 1 ); |
|
522 if ( iAction == EDbReadLock ) |
|
523 iAction = EDbWriteLock; |
|
524 if (iLockState == EDbReadLock ) |
|
525 iLockState = EDbXReadLock; // escalate lock to exclusive as we are now writing |
|
526 ++iUpdaters; |
|
527 iLockCount = 1; |
|
528 } |
|
529 |
|
530 void RDbTransaction::DMLTouch() |
|
531 // |
|
532 // This must be called prior to putting DML updates |
|
533 // |
|
534 { |
|
535 __ASSERT( iAction == EDbWriteLock ); |
|
536 __ASSERT( iUpdaters > 0 ); |
|
537 TInt ls = iLockState; |
|
538 if ( ls == EDbXReadLock ) |
|
539 ls = EDbWriteLock | EFailed; |
|
540 else |
|
541 ls |= EFailed; |
|
542 iLockState = TUint8( ls ); |
|
543 } |
|
544 |
|
545 void RDbTransaction::DMLBeginLC() |
|
546 { |
|
547 DMLBegin(); |
|
548 CleanupStack::PushL( TCleanupItem( DMLAbandon, this ) ); |
|
549 DMLTouch(); |
|
550 } |
|
551 |
|
552 void RDbTransaction::DMLCommitL() |
|
553 // |
|
554 // A rowset has completed an update |
|
555 // |
|
556 { |
|
557 __INVARIANT_L; |
|
558 __ASSERT( iAction == EDbWriteLock && ( iLockState & EFailed ) ); |
|
559 TInt updaters = iUpdaters - 1; |
|
560 if ( updaters == 0 ) |
|
561 { |
|
562 if ( ( iPrimary.iState & static_cast<TUint>( ETransactionLock ) ) == 0 ) |
|
563 { |
|
564 __ASSERT( iLockState == ( EDbWriteLock | EFailed ) ); |
|
565 DoCommitL(); // automatic write-commit, release auto-lock |
|
566 return; |
|
567 } |
|
568 iAction = EDbReadLock; |
|
569 } |
|
570 iUpdaters = updaters; |
|
571 iLockState &= ~EFailed; |
|
572 } |
|
573 |
|
574 void RDbTransaction::DMLRollback() |
|
575 // |
|
576 // Rollback a DML operation |
|
577 // |
|
578 { |
|
579 __INVARIANT; |
|
580 __ASSERT( iAction == EDbWriteLock ); |
|
581 TInt updates = iUpdaters - 1; |
|
582 if ( updates == 0 ) |
|
583 { |
|
584 if ( ( iPrimary.iState & static_cast<TUint>( ETransactionLock ) ) == 0 ) |
|
585 { |
|
586 __ASSERT( LockState() == EDbWriteLock || LockState() == EDbXReadLock ); |
|
587 DoRollback(); // automatic rollback now (may panic) |
|
588 return; |
|
589 } |
|
590 iAction = EDbReadLock; |
|
591 } |
|
592 iUpdaters = updates; |
|
593 } |
|
594 |
|
595 void RDbTransaction::DMLAbandon( TAny* aPtr ) |
|
596 { |
|
597 STATIC_CAST( RDbTransaction*, aPtr )->DMLRollback(); |
|
598 } |
|
599 |
|
600 void RDbTransaction::DDLPrepareL( const CDbObject& aObject ) |
|
601 // |
|
602 // Check that we can use the database for ddl and flush out any tables |
|
603 // should be called before DDLBegin |
|
604 // |
|
605 { |
|
606 __INVARIANT_L; |
|
607 ReadyL(); |
|
608 PrepareXLockL( aObject ); |
|
609 if ( iAction != EDbReadLock || ( IsLocked() && iPrimary.iState != static_cast<TUint>( ETransactionLock ) ) ) |
|
610 __LEAVE( KErrAccessDenied ); // Cannot take sole ownership of the database |
|
611 TInt ls = iLockState; |
|
612 if ( ls >= EDbWriteLock ) |
|
613 { // ensure all table data is flushed as they may be "released" |
|
614 iLockState = TUint8( ls | EFailed ); |
|
615 Database().FlushL( EDbWriteLock ); |
|
616 iLockState = TUint8( ls ); |
|
617 } |
|
618 } |
|
619 |
|
620 void RDbTransaction::DDLBegin() |
|
621 // |
|
622 // A DDL object is about to start ops |
|
623 // |
|
624 { |
|
625 __INVARIANT; |
|
626 __ASSERT( iAction == EDbReadLock ); |
|
627 __ASSERT( ( iLockState & EFailed ) == 0 ); |
|
628 __ASSERT( iLockCount <= 1 ); |
|
629 iLockState = iAction = EDbSchemaLock; |
|
630 iLockCount = 1; |
|
631 } |
|
632 |
|
633 void RDbTransaction::DDLBeginLC() |
|
634 { |
|
635 DDLBegin(); |
|
636 CleanupStack::PushL( TCleanupItem( DDLAbandon, this ) ); |
|
637 } |
|
638 |
|
639 void RDbTransaction::DDLCommitL() |
|
640 // |
|
641 // A DDL incremental object has completed |
|
642 // |
|
643 { |
|
644 __INVARIANT_L; |
|
645 __ASSERT( iAction == EDbSchemaLock ); |
|
646 if ( ( iPrimary.iState & static_cast<TUint>( ETransactionLock ) ) == 0 ) |
|
647 { |
|
648 __ASSERT( iLockState == EDbSchemaLock ); |
|
649 DoCommitL(); // release auto-lock |
|
650 } |
|
651 else |
|
652 iAction = EDbReadLock; |
|
653 } |
|
654 |
|
655 void RDbTransaction::DDLRollback() |
|
656 // |
|
657 // Rollback a DDL operation |
|
658 // |
|
659 { |
|
660 __INVARIANT; |
|
661 __ASSERT( iAction == EDbSchemaLock ); |
|
662 iLockState |= EFailed; |
|
663 if ( ( iPrimary.iState & static_cast<TUint>( ETransactionLock ) ) == 0 ) |
|
664 { |
|
665 __ASSERT( iLockState == ( EDbSchemaLock | EFailed ) ); |
|
666 DoRollback(); // release auto-lock |
|
667 } |
|
668 else |
|
669 iAction = EDbReadLock; |
|
670 } |
|
671 |
|
672 void RDbTransaction::DDLAbandon( TAny* aPtr ) |
|
673 { |
|
674 STATIC_CAST( RDbTransaction*, aPtr )->DDLRollback(); |
|
675 } |
|
676 |
|
677 // recovery. Nothing else can be done at the same time as this |
|
678 |
|
679 void RDbTransaction::UtilityPrepareL( const CDbObject& aObject ) |
|
680 // |
|
681 // Check that we are in a state to run a utility |
|
682 // |
|
683 { |
|
684 __INVARIANT_L; |
|
685 ReadyL(); |
|
686 PrepareXLockL( aObject ); |
|
687 if ( IsLocked() ) // utilities not allowed in user transaction |
|
688 __LEAVE( KErrAccessDenied ); |
|
689 } |
|
690 |
|
691 void RDbTransaction::UtilityBegin( CDbDatabase::TUtility aType ) |
|
692 // |
|
693 // Database Recovery object is about to start |
|
694 // |
|
695 { |
|
696 __INVARIANT; |
|
697 __ASSERT( !IsLocked() ); |
|
698 if ( aType == CDbDatabase::ERecover ) |
|
699 iLockState = iAction = EDbRecoveryLock; |
|
700 else |
|
701 iLockState = iAction = EDbCompactLock; |
|
702 iLockCount = 1; |
|
703 } |
|
704 |
|
705 void RDbTransaction::UtilityCommitL() |
|
706 // |
|
707 // Database Recovery has completed |
|
708 // |
|
709 { |
|
710 __INVARIANT_L; |
|
711 Database().SynchL( LockState() ); |
|
712 Unlock( iAction == EDbRecoveryLock ? RDbNotifier::ERecover : RDbNotifier::EUnlock ); // release auto-lock |
|
713 } |
|
714 |
|
715 void RDbTransaction::UtilityRollback() |
|
716 { |
|
717 __INVARIANT; |
|
718 Database().Revert( LockState() ); |
|
719 Unlock( RDbNotifier::EUnlock ); // release auto-lock |
|
720 } |
|
721 |
|
722 CDbNotifier* RDbTransaction::NotifierL() |
|
723 // |
|
724 // Only support a single notifier for the database (server multiplexes) |
|
725 // |
|
726 { |
|
727 if ( iNotifier ) |
|
728 __LEAVE( KErrNotSupported ); |
|
729 return iNotifier = new( ELeave ) CNotifier( *this ); |
|
730 } |
|
731 |
|
732 void RDbTransaction::Event( RDbNotifier::TEvent aEvent ) |
|
733 // |
|
734 // Report an event to the Notifier |
|
735 // If the lock was less than a write lock, report unlock only: no commit or rollback |
|
736 // |
|
737 { |
|
738 // if ( iNotifier ) |
|
739 // iNotifier->Event( aEvent ); |
|
740 } |
|
741 |
|
742 |