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