persistentstorage/dbms/pcdbms/utable/UT_TRANS.CPP
changeset 0 08ec8eefde2f
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     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