os/persistentdata/persistentstorage/dbms/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
#else // _ASSERTIONS
sl@0
   225
sl@0
   226
#define __INVARIANT   ( (void)0 )
sl@0
   227
#define __INVARIANT_L ( (void)0 )
sl@0
   228
sl@0
   229
#endif // _ASSERTIONS
sl@0
   230
sl@0
   231
inline TDbLockType RDbTransaction::LockState() const
sl@0
   232
	{ return TDbLockType( iLockState & EState ); }
sl@0
   233
sl@0
   234
void RDbTransaction::Close()
sl@0
   235
	{
sl@0
   236
	__ASSERT( !IsLocked() );
sl@0
   237
	User::Free( iSharers );
sl@0
   238
	Event( RDbNotifier::EClose );
sl@0
   239
	}
sl@0
   240
sl@0
   241
void RDbTransaction::DoCommitL()
sl@0
   242
//
sl@0
   243
// Commit any changes
sl@0
   244
//
sl@0
   245
	{
sl@0
   246
	__ASSERT_ALWAYS( ( iPrimary.iState & ~ETransactionLock ) == 0, Panic( EDbStreamsPendingOnCommit ) );
sl@0
   247
	iLockState |= EFailed;
sl@0
   248
	Database().FlushL( LockState() );
sl@0
   249
	Database().SynchL( LockState() );
sl@0
   250
	Unlock( RDbNotifier::ECommit );
sl@0
   251
	}
sl@0
   252
sl@0
   253
void RDbTransaction::DoRollback()
sl@0
   254
//
sl@0
   255
// Rollback any changes
sl@0
   256
//
sl@0
   257
	{
sl@0
   258
	__ASSERT_ALWAYS( ( iPrimary.iState & ~ETransactionLock ) == 0, Panic( EDbStreamsPendingOnRollback ) );
sl@0
   259
	Database().Revert( LockState() );
sl@0
   260
	Database().Abandon( LockState() );
sl@0
   261
	if ( LockState() >= EDbWriteLock )
sl@0
   262
		++iRollback;
sl@0
   263
	Unlock( RDbNotifier::ERollback );
sl@0
   264
	}
sl@0
   265
sl@0
   266
// explicit transactions
sl@0
   267
sl@0
   268
void RDbTransaction::BeginL( const CDbObject& aObject )
sl@0
   269
//
sl@0
   270
// begin a user transaction. This first gains a shared read-lock
sl@0
   271
//
sl@0
   272
	{
sl@0
   273
	__INVARIANT_L;
sl@0
   274
	__ASSERT_ALWAYS( GetLock( aObject ) == 0, Panic( EDbBeginNestedTransaction ) );
sl@0
   275
	ReadyL();
sl@0
   276
	PrepareSLockL( aObject, TUint( ETransactionLock ) );
sl@0
   277
	__ASSERT( iAction == EDbReadLock );
sl@0
   278
	__ASSERT( iLockState == EDbReadLock );
sl@0
   279
	++iLockCount;
sl@0
   280
	}
sl@0
   281
sl@0
   282
void RDbTransaction::CommitL( const CDbObject& aObject )
sl@0
   283
//
sl@0
   284
// Commit a user transaction and release the lock
sl@0
   285
// All updates must be complete for a write-lock
sl@0
   286
//
sl@0
   287
	{
sl@0
   288
	__INVARIANT_L;
sl@0
   289
	__ASSERT_ALWAYS( InTransaction( aObject ), Panic( EDbNoCurrentTransaction ) );
sl@0
   290
	ReadyL();
sl@0
   291
	if ( iLockCount > 1 )
sl@0
   292
		{
sl@0
   293
		TLock* lock = GetLock( aObject );
sl@0
   294
		__ASSERT( lock );
sl@0
   295
		__ASSERT_ALWAYS( lock->iState == static_cast<TUint>( ETransactionLock ), Panic( EDbStreamsPendingOnCommit ) );
sl@0
   296
		Unlock( *lock );
sl@0
   297
		}
sl@0
   298
	else
sl@0
   299
		{
sl@0
   300
		__ASSERT_ALWAYS( iAction == EDbReadLock, Panic( EDbUpdatesPendingOnCommit ) );
sl@0
   301
		DoCommitL();
sl@0
   302
		}
sl@0
   303
	}
sl@0
   304
sl@0
   305
void RDbTransaction::Rollback( const CDbObject& aObject )
sl@0
   306
//
sl@0
   307
// Rollback a user transaction and release the lock
sl@0
   308
// All updates must be complete/aborted for a write-lock
sl@0
   309
//
sl@0
   310
	{
sl@0
   311
	__INVARIANT;
sl@0
   312
	__ASSERT_ALWAYS( InTransaction( aObject ), Panic( EDbNoCurrentTransaction ) );
sl@0
   313
	if ( iLockCount > 1 )
sl@0
   314
		{
sl@0
   315
		TLock* lock = GetLock( aObject );
sl@0
   316
		__ASSERT( lock );
sl@0
   317
		__ASSERT_ALWAYS( lock->iState == static_cast<TUint>( ETransactionLock ), Panic( EDbStreamsPendingOnRollback ) );
sl@0
   318
		Unlock( *lock );
sl@0
   319
		}
sl@0
   320
	else
sl@0
   321
		{
sl@0
   322
		__ASSERT_ALWAYS( iAction == EDbReadLock, Panic( EDbUpdatesPendingOnRollback ) );
sl@0
   323
		DoRollback();
sl@0
   324
		}
sl@0
   325
	}
sl@0
   326
sl@0
   327
void RDbTransaction::PrepareSLockL( const CDbObject& aObject, TUint aInitState )
sl@0
   328
//
sl@0
   329
// prepare to acquire a shared read lock
sl@0
   330
// if any holder has an exclusive lock this fails
sl@0
   331
//
sl@0
   332
	{
sl@0
   333
	__ASSERT( GetLock( aObject ) == 0 );	// cannot get a 2nd shared lock
sl@0
   334
//
sl@0
   335
	THolder h = aObject.Context();
sl@0
   336
	if ( iLockCount == 0 )
sl@0
   337
		{
sl@0
   338
		iPrimary.iHolder = h;				// first lock, no other checks required
sl@0
   339
		iPrimary.iState = aInitState;
sl@0
   340
		}
sl@0
   341
	else if ( iLockState != EDbReadLock )
sl@0
   342
		__LEAVE( KErrLocked );
sl@0
   343
	else
sl@0
   344
		{						// allocate a Sharers-slot
sl@0
   345
		TLock* share = iSharers;
sl@0
   346
		if ( iLockCount == iMaxLock )
sl@0
   347
			{
sl@0
   348
			TInt newsize = iMaxLock + ELockListGranularity;
sl@0
   349
			if ( newsize > EMaxLock )
sl@0
   350
				{
sl@0
   351
				__LEAVE( KErrLocked );
sl@0
   352
				return;
sl@0
   353
				}
sl@0
   354
			iSharers = share = ( TLock* )User::ReAllocL( share, ( newsize - 1 ) * sizeof( TLock ) );
sl@0
   355
			iMaxLock = TUint8( newsize );
sl@0
   356
			}
sl@0
   357
		share += iLockCount - 1;
sl@0
   358
		share->iHolder = h;
sl@0
   359
		share->iState = aInitState;
sl@0
   360
		}
sl@0
   361
	}
sl@0
   362
sl@0
   363
void RDbTransaction::PrepareXLockL( const CDbObject& aObject )
sl@0
   364
//
sl@0
   365
// prepare to acquire an exclusive lock
sl@0
   366
// if any other holder has a lock this fails
sl@0
   367
//
sl@0
   368
	{
sl@0
   369
	THolder h = aObject.Context();
sl@0
   370
	switch ( iLockCount )
sl@0
   371
		{
sl@0
   372
	case 0:					// no other holders, acquire the lock
sl@0
   373
		iPrimary.iHolder = h;
sl@0
   374
		iPrimary.iState = 0;		// this is not a transaction lock
sl@0
   375
		break;
sl@0
   376
	case 1:					// check we are the single Lock holder
sl@0
   377
		if (iPrimary.iHolder != h)
sl@0
   378
			__LEAVE( KErrLocked );
sl@0
   379
		break;
sl@0
   380
	default:				// cannot get XLock
sl@0
   381
		__LEAVE( KErrLocked );
sl@0
   382
		break;
sl@0
   383
		}
sl@0
   384
	}
sl@0
   385
sl@0
   386
void RDbTransaction::Unlock( RDbNotifier::TEvent aEvent )
sl@0
   387
//
sl@0
   388
// Remove the last lock and signal an event to the Notifier
sl@0
   389
//
sl@0
   390
	{
sl@0
   391
	__ASSERT( iLockCount == 1 );
sl@0
   392
	__ASSERT( ( iPrimary.iState & ~ETransactionLock ) == 0 );
sl@0
   393
	TDbLockType ls = LockState();
sl@0
   394
	Event( ls == EDbReadLock || ls == EDbXReadLock ? RDbNotifier::EUnlock : aEvent );
sl@0
   395
	iLockCount = 0;
sl@0
   396
	iAction = iLockState = EDbReadLock;
sl@0
   397
	iUpdaters = 0;
sl@0
   398
	Database().CheckIdle();
sl@0
   399
	}
sl@0
   400
sl@0
   401
void RDbTransaction::Unlock( RDbTransaction::TLock& aLock )
sl@0
   402
//
sl@0
   403
// Remove a shared lock holder from the list
sl@0
   404
//
sl@0
   405
	{
sl@0
   406
	__ASSERT( iLockCount > 1 );
sl@0
   407
	__ASSERT( LockState() == EDbReadLock );
sl@0
   408
	__ASSERT( ( aLock.iState & ~ETransactionLock ) == 0 );
sl@0
   409
	aLock = iSharers[--iLockCount - 1];
sl@0
   410
	}
sl@0
   411
sl@0
   412
RDbTransaction::TLock* RDbTransaction::GetLock( const CDbObject& aObject )
sl@0
   413
//
sl@0
   414
// Test if aObject holds any lock, and return it
sl@0
   415
//
sl@0
   416
	{
sl@0
   417
	const THolder h = aObject.Context();
sl@0
   418
	TInt lc = iLockCount;
sl@0
   419
	if ( --lc >= 0 )
sl@0
   420
		{
sl@0
   421
		if ( iPrimary.iHolder == h )
sl@0
   422
			return &iPrimary;
sl@0
   423
		if ( lc > 0 )
sl@0
   424
			{
sl@0
   425
			TLock* const base = iSharers;
sl@0
   426
			TLock* l = base + lc;
sl@0
   427
			do	{
sl@0
   428
				if ( ( --l )->iHolder == h )
sl@0
   429
					return l;
sl@0
   430
				} while ( l > base );
sl@0
   431
			}
sl@0
   432
		}
sl@0
   433
	return 0;
sl@0
   434
	}
sl@0
   435
sl@0
   436
TBool RDbTransaction::InTransaction( const CDbObject& aObject )
sl@0
   437
//
sl@0
   438
// Test if aObject holds a non-auto transaction
sl@0
   439
//
sl@0
   440
	{
sl@0
   441
	__INVARIANT;
sl@0
   442
	TLock* lock = GetLock( aObject );
sl@0
   443
	return lock ? lock->iState & static_cast<TUint>( ETransactionLock ) : 0;
sl@0
   444
	}
sl@0
   445
sl@0
   446
void RDbTransaction::ReadPrepareL( const CDbObject& aObject )
sl@0
   447
//
sl@0
   448
// Check that aObject can gain a shared read lock and allocate required resources
sl@0
   449
//
sl@0
   450
	{
sl@0
   451
	__INVARIANT_L;
sl@0
   452
	if ( GetLock( aObject ) == 0 )
sl@0
   453
		PrepareSLockL( aObject, 0 );		// prepare a S-Lock for the read
sl@0
   454
	else if ( iAction == EDbCompactLock )	// Cannot already hold a compaction lock
sl@0
   455
		__LEAVE( KErrAccessDenied );
sl@0
   456
	}
sl@0
   457
sl@0
   458
void RDbTransaction::ReadBegin( const CDbObject& aObject )
sl@0
   459
//
sl@0
   460
// Take a read-lock: ReadPrepareL(aObject) _must_ already have been called
sl@0
   461
//
sl@0
   462
	{
sl@0
   463
	__INVARIANT;
sl@0
   464
	TLock* lock = GetLock( aObject );
sl@0
   465
	if ( !lock )
sl@0
   466
		{
sl@0
   467
		++iLockCount;
sl@0
   468
		lock = GetLock( aObject );
sl@0
   469
		__ASSERT( lock );
sl@0
   470
		}
sl@0
   471
	++lock->iState;
sl@0
   472
	}
sl@0
   473
sl@0
   474
void RDbTransaction::ReadRelease( const CDbObject& aObject )
sl@0
   475
	{
sl@0
   476
	__INVARIANT;
sl@0
   477
	TLock* lock = GetLock( aObject );
sl@0
   478
	__ASSERT( lock );
sl@0
   479
	__ASSERT( ( lock->iState & ~ETransactionLock ) > 0 );
sl@0
   480
	if ( --lock->iState == 0 )
sl@0
   481
		{	// not transaction-lock
sl@0
   482
		if ( iLockCount > 1 )
sl@0
   483
			Unlock( *lock );
sl@0
   484
		else if ( iAction == EDbReadLock )	// no other locks to this client
sl@0
   485
			Unlock( RDbNotifier::EUnlock );
sl@0
   486
		}
sl@0
   487
	}
sl@0
   488
sl@0
   489
void RDbTransaction::DMLCheckL()
sl@0
   490
//
sl@0
   491
// Check that we can open a new rowset
sl@0
   492
//
sl@0
   493
	{
sl@0
   494
	__INVARIANT_L;
sl@0
   495
	ReadyL();
sl@0
   496
	if ( iAction > EDbCompactLock )	
sl@0
   497
		__LEAVE( KErrAccessDenied );
sl@0
   498
	}
sl@0
   499
sl@0
   500
void RDbTransaction::DMLPrepareL( const CDbObject& aObject )
sl@0
   501
//
sl@0
   502
// Check that we can do DML, this should be called immediately prior to DMLBegin
sl@0
   503
//
sl@0
   504
	{
sl@0
   505
	__INVARIANT_L;
sl@0
   506
	PrepareXLockL( aObject );
sl@0
   507
	if ( iAction>EDbWriteLock )
sl@0
   508
		__LEAVE( KErrAccessDenied );
sl@0
   509
	}
sl@0
   510
sl@0
   511
void RDbTransaction::DMLBegin()
sl@0
   512
//
sl@0
   513
// A Rowset begins an update
sl@0
   514
//
sl@0
   515
	{
sl@0
   516
	__INVARIANT;
sl@0
   517
	__ASSERT( iAction == EDbReadLock || iAction == EDbWriteLock );
sl@0
   518
	__ASSERT( ( iLockState & EFailed ) == 0 );
sl@0
   519
	__ASSERT( iLockCount <= 1 );
sl@0
   520
	if ( iAction == EDbReadLock )
sl@0
   521
		iAction = EDbWriteLock;
sl@0
   522
	if (iLockState == EDbReadLock )
sl@0
   523
		iLockState = EDbXReadLock;		// escalate lock to exclusive as we are now writing
sl@0
   524
	++iUpdaters;
sl@0
   525
	iLockCount = 1;
sl@0
   526
	}
sl@0
   527
sl@0
   528
void RDbTransaction::DMLTouch()
sl@0
   529
//
sl@0
   530
// This must be called prior to putting DML updates
sl@0
   531
//
sl@0
   532
	{
sl@0
   533
	__ASSERT( iAction == EDbWriteLock );
sl@0
   534
	__ASSERT( iUpdaters > 0 );
sl@0
   535
	TInt ls = iLockState;
sl@0
   536
	if ( ls == EDbXReadLock )
sl@0
   537
		ls = EDbWriteLock | EFailed;
sl@0
   538
	else
sl@0
   539
		ls |= EFailed;
sl@0
   540
	iLockState = TUint8( ls );
sl@0
   541
	}
sl@0
   542
sl@0
   543
void RDbTransaction::DMLBeginLC()
sl@0
   544
	{
sl@0
   545
	DMLBegin();
sl@0
   546
	CleanupStack::PushL( TCleanupItem( DMLAbandon, this ) );
sl@0
   547
	DMLTouch();
sl@0
   548
	}
sl@0
   549
sl@0
   550
void RDbTransaction::DMLCommitL()
sl@0
   551
//
sl@0
   552
// A rowset has completed an update
sl@0
   553
//
sl@0
   554
	{
sl@0
   555
	__INVARIANT_L;
sl@0
   556
	__ASSERT( iAction == EDbWriteLock && ( iLockState & EFailed ) );
sl@0
   557
	TInt updaters = iUpdaters - 1;
sl@0
   558
	if ( updaters == 0 )
sl@0
   559
		{
sl@0
   560
		if ( ( iPrimary.iState & static_cast<TUint>( ETransactionLock ) ) == 0 )
sl@0
   561
			{
sl@0
   562
			__ASSERT( iLockState == ( EDbWriteLock | EFailed ) );
sl@0
   563
			DoCommitL();		// automatic write-commit, release auto-lock
sl@0
   564
			return;
sl@0
   565
			}
sl@0
   566
		iAction = EDbReadLock;
sl@0
   567
		}
sl@0
   568
	iUpdaters = updaters;
sl@0
   569
	iLockState &= ~EFailed;
sl@0
   570
	}
sl@0
   571
sl@0
   572
void RDbTransaction::DMLRollback()
sl@0
   573
//
sl@0
   574
// Rollback a DML operation
sl@0
   575
//
sl@0
   576
	{
sl@0
   577
	__INVARIANT;
sl@0
   578
	__ASSERT( iAction == EDbWriteLock );
sl@0
   579
	TInt updates = iUpdaters - 1;
sl@0
   580
	if ( updates == 0 )
sl@0
   581
		{
sl@0
   582
		if ( ( iPrimary.iState & static_cast<TUint>( ETransactionLock ) ) == 0 )
sl@0
   583
			{
sl@0
   584
			__ASSERT( LockState() == EDbWriteLock || LockState() == EDbXReadLock );
sl@0
   585
			DoRollback();		// automatic rollback now (may panic)
sl@0
   586
			return;
sl@0
   587
			}
sl@0
   588
		iAction = EDbReadLock;
sl@0
   589
		}
sl@0
   590
	iUpdaters = updates;
sl@0
   591
	}
sl@0
   592
sl@0
   593
void RDbTransaction::DMLAbandon( TAny* aPtr )
sl@0
   594
	{
sl@0
   595
	STATIC_CAST( RDbTransaction*, aPtr )->DMLRollback();
sl@0
   596
	}
sl@0
   597
sl@0
   598
void RDbTransaction::DDLPrepareL( const CDbObject& aObject )
sl@0
   599
//
sl@0
   600
// Check that we can use the database for ddl and flush out any tables
sl@0
   601
// should be called before DDLBegin
sl@0
   602
//
sl@0
   603
	{
sl@0
   604
	__INVARIANT_L;
sl@0
   605
	ReadyL();
sl@0
   606
	PrepareXLockL( aObject );
sl@0
   607
	if ( iAction != EDbReadLock || ( IsLocked() && iPrimary.iState != static_cast<TUint>( ETransactionLock ) ) )
sl@0
   608
		__LEAVE( KErrAccessDenied );	// Cannot take sole ownership of the database
sl@0
   609
	TInt ls = iLockState;
sl@0
   610
	if ( ls >= EDbWriteLock )
sl@0
   611
		{	// ensure all table data is flushed as they may be "released"
sl@0
   612
		iLockState = TUint8( ls | EFailed );
sl@0
   613
		Database().FlushL( EDbWriteLock );
sl@0
   614
		iLockState = TUint8( ls );
sl@0
   615
		}
sl@0
   616
	}
sl@0
   617
sl@0
   618
void RDbTransaction::DDLBegin()
sl@0
   619
//
sl@0
   620
// A DDL object is about to start ops
sl@0
   621
//
sl@0
   622
	{
sl@0
   623
	__INVARIANT;
sl@0
   624
	__ASSERT( iAction == EDbReadLock );
sl@0
   625
	__ASSERT( ( iLockState & EFailed ) == 0 );
sl@0
   626
	__ASSERT( iLockCount <= 1 );
sl@0
   627
	iLockState = iAction = EDbSchemaLock;
sl@0
   628
	iLockCount = 1;
sl@0
   629
	}
sl@0
   630
sl@0
   631
void RDbTransaction::DDLBeginLC()
sl@0
   632
	{
sl@0
   633
	DDLBegin();
sl@0
   634
	CleanupStack::PushL( TCleanupItem( DDLAbandon, this ) );
sl@0
   635
	}
sl@0
   636
sl@0
   637
void RDbTransaction::DDLCommitL()
sl@0
   638
//
sl@0
   639
// A DDL incremental object has completed
sl@0
   640
//
sl@0
   641
	{
sl@0
   642
	__INVARIANT_L;
sl@0
   643
	__ASSERT( iAction == EDbSchemaLock );
sl@0
   644
	if ( ( iPrimary.iState & static_cast<TUint>( ETransactionLock ) ) == 0 )
sl@0
   645
		{
sl@0
   646
		__ASSERT( iLockState == EDbSchemaLock );
sl@0
   647
		DoCommitL();	// release auto-lock
sl@0
   648
		}
sl@0
   649
	else
sl@0
   650
		iAction = EDbReadLock;
sl@0
   651
	}
sl@0
   652
sl@0
   653
void RDbTransaction::DDLRollback()
sl@0
   654
//
sl@0
   655
// Rollback a DDL operation
sl@0
   656
//
sl@0
   657
	{
sl@0
   658
	__INVARIANT;
sl@0
   659
	__ASSERT( iAction == EDbSchemaLock );
sl@0
   660
	iLockState |= EFailed;
sl@0
   661
	if ( ( iPrimary.iState & static_cast<TUint>( ETransactionLock ) ) == 0 )
sl@0
   662
		{
sl@0
   663
		__ASSERT( iLockState == ( EDbSchemaLock | EFailed ) );
sl@0
   664
		DoRollback();		// release auto-lock
sl@0
   665
		}
sl@0
   666
	else
sl@0
   667
		iAction = EDbReadLock;
sl@0
   668
	}
sl@0
   669
sl@0
   670
void RDbTransaction::DDLAbandon( TAny* aPtr )
sl@0
   671
	{
sl@0
   672
	STATIC_CAST( RDbTransaction*, aPtr )->DDLRollback();
sl@0
   673
	}
sl@0
   674
sl@0
   675
// recovery. Nothing else can be done at the same time as this
sl@0
   676
sl@0
   677
void RDbTransaction::UtilityPrepareL( const CDbObject& aObject )
sl@0
   678
//
sl@0
   679
// Check that we are in a state to run a utility
sl@0
   680
//
sl@0
   681
	{
sl@0
   682
	__INVARIANT_L;
sl@0
   683
	ReadyL();
sl@0
   684
	PrepareXLockL( aObject );
sl@0
   685
	if ( IsLocked() )			// utilities not allowed in user transaction
sl@0
   686
		__LEAVE( KErrAccessDenied );
sl@0
   687
	}
sl@0
   688
sl@0
   689
void RDbTransaction::UtilityBegin( CDbDatabase::TUtility aType )
sl@0
   690
//
sl@0
   691
// Database Recovery object is about to start
sl@0
   692
//
sl@0
   693
	{
sl@0
   694
	__INVARIANT;
sl@0
   695
	__ASSERT( !IsLocked() );
sl@0
   696
	if ( aType == CDbDatabase::ERecover )
sl@0
   697
		iLockState = iAction = EDbRecoveryLock;
sl@0
   698
	else
sl@0
   699
		iLockState = iAction = EDbCompactLock;
sl@0
   700
	iLockCount = 1;
sl@0
   701
	}
sl@0
   702
sl@0
   703
void RDbTransaction::UtilityCommitL()
sl@0
   704
//
sl@0
   705
// Database Recovery has completed
sl@0
   706
//
sl@0
   707
	{
sl@0
   708
	__INVARIANT_L;
sl@0
   709
	Database().SynchL( LockState() );
sl@0
   710
	Unlock( iAction == EDbRecoveryLock ? RDbNotifier::ERecover : RDbNotifier::EUnlock );	// release auto-lock
sl@0
   711
	}
sl@0
   712
sl@0
   713
void RDbTransaction::UtilityRollback()
sl@0
   714
	{
sl@0
   715
	__INVARIANT;
sl@0
   716
	Database().Revert( LockState() );
sl@0
   717
	Unlock( RDbNotifier::EUnlock );	// release auto-lock
sl@0
   718
	}
sl@0
   719
sl@0
   720
CDbNotifier* RDbTransaction::NotifierL()
sl@0
   721
//
sl@0
   722
// Only support a single notifier for the database (server multiplexes)
sl@0
   723
//
sl@0
   724
	{
sl@0
   725
	if ( iNotifier )
sl@0
   726
		__LEAVE( KErrNotSupported );
sl@0
   727
	return iNotifier = new( ELeave ) CNotifier( *this );
sl@0
   728
	}
sl@0
   729
sl@0
   730
void RDbTransaction::Event( RDbNotifier::TEvent aEvent )
sl@0
   731
//
sl@0
   732
// Report an event to the Notifier
sl@0
   733
// If the lock was less than a write lock, report unlock only: no commit or rollback
sl@0
   734
//
sl@0
   735
	{
sl@0
   736
	if ( iNotifier )
sl@0
   737
		iNotifier->Event( aEvent );
sl@0
   738
	}
sl@0
   739
sl@0
   740