|
1 // Copyright (c) 2008-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 <e32debug.h> |
|
17 #include <hal.h> |
|
18 #include <sqldb.h> |
|
19 #include "SqlPanic.h" |
|
20 #include "SqlCompactEntry.h" |
|
21 #include "SqlCompactTimer.h" |
|
22 #include "SqliteSymbian.h" //TSqlFreePageCallback |
|
23 |
|
24 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
25 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
26 |
|
27 /** |
|
28 Creates a new CSqlCompactEntry instance. |
|
29 |
|
30 @param aFullName The full database name, including the path. |
|
31 @param aConnFactoryL MSqlCompactConn factory function. |
|
32 @param aSettings Background compaction settings/thresholds |
|
33 @param aTimer The background compaction timer object |
|
34 |
|
35 When the free pages threshold reach certain the threshold, the background compaction |
|
36 for this entry will be kicked-off. |
|
37 |
|
38 @return A pointer to the created CSqlCompactEntry instance |
|
39 |
|
40 @leave KErrNoMemory, an out of memory condition has occurred; |
|
41 Note that the function may also leave with some other database specific |
|
42 errors categorised as ESqlDbError, and other system-wide error codes. |
|
43 |
|
44 @panic SqlDb 4 In _DEBUG mode. Too short or too long database name (aFullName parameter) |
|
45 @panic SqlDb 4 In _DEBUG mode. NULL aConnFactoryL. |
|
46 */ |
|
47 CSqlCompactEntry* CSqlCompactEntry::NewLC(const TDesC& aFullName, TSqlCompactConnFactoryL aConnFactoryL, |
|
48 const TSqlCompactSettings& aSettings, CSqlCompactTimer& aTimer) |
|
49 { |
|
50 __SQLASSERT(aFullName.Length() > 0 && aFullName.Length() <= KMaxFileName, ESqlPanicBadArgument); |
|
51 __SQLASSERT(aConnFactoryL != NULL, ESqlPanicBadArgument); |
|
52 CSqlCompactEntry* self = new (ELeave) CSqlCompactEntry(aSettings, aTimer); |
|
53 CleanupStack::PushL(self); |
|
54 self->ConstructL(aFullName, aConnFactoryL); |
|
55 return self; |
|
56 } |
|
57 |
|
58 /** |
|
59 Destroys the CSqlCompactEntry instance. The database connection will be closed. |
|
60 */ |
|
61 CSqlCompactEntry::~CSqlCompactEntry() |
|
62 { |
|
63 if(iState == CSqlCompactEntry::EInProgress) |
|
64 { |
|
65 iTimer.DeQueue(*this); |
|
66 } |
|
67 if(iConnection) |
|
68 { |
|
69 iConnection->Release(); |
|
70 } |
|
71 iFullName.Close(); |
|
72 } |
|
73 |
|
74 /** |
|
75 Increments the entry reference counter. |
|
76 |
|
77 @return The new reference counter value. |
|
78 */ |
|
79 TInt CSqlCompactEntry::AddRef() |
|
80 { |
|
81 SQLCOMPACTENTRY_INVARIANT(); |
|
82 return ++iRefCounter; |
|
83 } |
|
84 |
|
85 /** |
|
86 Decrements the entry reference counter. |
|
87 If the counter reaches zero, the CSqlCompactEntry instance will be destroyed. |
|
88 |
|
89 @return The new reference counter value. |
|
90 */ |
|
91 TInt CSqlCompactEntry::Release() |
|
92 { |
|
93 SQLCOMPACTENTRY_INVARIANT(); |
|
94 TInt rc = --iRefCounter; |
|
95 if(rc == 0) |
|
96 { |
|
97 delete this; |
|
98 } |
|
99 return rc; |
|
100 } |
|
101 |
|
102 /** |
|
103 SQLite calls this function when the free pages count reaches the threshold. |
|
104 The callback must have been registered at the moment of the database connection creation in order this to happen. |
|
105 The callback implementation will schedule a background compaction (kicking-off the timer). |
|
106 If a background compaction has already been scheduled, the implementation will only update the iPageCount data |
|
107 meber value. |
|
108 |
|
109 @param aThis A pointer to the CSqlCompactEntry object for which the free page count reached or is above the threshold. |
|
110 @param aFreePageCount Free pages count. |
|
111 |
|
112 @panic SqlDb 4 In _DEBUG mode. NULL aThis parameter. |
|
113 @panic SqlDb 4 In _DEBUG mode. aFreePageCount is negative or zero. |
|
114 */ |
|
115 /* static */ void CSqlCompactEntry::FreePageCallback(void* aThis, TInt aFreePageCount) |
|
116 { |
|
117 __SQLASSERT(aThis != NULL, ESqlPanicBadArgument); |
|
118 __SQLASSERT(aFreePageCount > 0, ESqlPanicBadArgument); |
|
119 |
|
120 CSqlCompactEntry& entry = *(static_cast <CSqlCompactEntry*> (aThis)); |
|
121 if(entry.iFreePageCallbackDisabled) |
|
122 {//The callback is disabled during the background compaction step. |
|
123 //The server is single-threaded, so no other client can activate the callback. |
|
124 //During the background compaction step the callback can be activated only by the completion of the background |
|
125 //compaction in which case if "entry.iPageCount" is bigger than the threshold, the page counter will be set from here |
|
126 //and set second time from CSqlCompactEntry::Compact() - the counter value will be reduced twice. |
|
127 return; |
|
128 } |
|
129 |
|
130 entry.iPageCount = aFreePageCount; |
|
131 if(entry.iState == CSqlCompactEntry::EInactive) |
|
132 { |
|
133 entry.iState = CSqlCompactEntry::EInProgress; |
|
134 entry.iTimer.Queue(entry); |
|
135 } |
|
136 } |
|
137 |
|
138 /** |
|
139 Initializes the CSqlCompactEntry data members with their default values. |
|
140 |
|
141 @param aSettings Background compaction settings/thresholds |
|
142 */ |
|
143 CSqlCompactEntry::CSqlCompactEntry(const TSqlCompactSettings& aSettings, CSqlCompactTimer& aTimer) : |
|
144 iSettings(aSettings), |
|
145 iTimer(aTimer), |
|
146 iRefCounter(1), |
|
147 iState(CSqlCompactEntry::EInactive) |
|
148 { |
|
149 } |
|
150 |
|
151 /** |
|
152 Initializes the created CSqlCompactEntry instance. |
|
153 Schedules a background compaction if the free pages count is above the threshold. |
|
154 |
|
155 @param aFullName The full database name, including the path. |
|
156 @param aConnFactoryL MSqlCompactConn factory function. |
|
157 |
|
158 @panic SqlDb 4 In _DEBUG mode. Too short or too long database name (aFullName parameter) |
|
159 @panic SqlDb 4 In _DEBUG mode. NULL aConnFactoryL. |
|
160 @panic SqlDb 7 In _DEBUG mode. The CSqlCompactEntry instance has been initialized already. |
|
161 */ |
|
162 void CSqlCompactEntry::ConstructL(const TDesC& aFullName, TSqlCompactConnFactoryL aConnFactoryL) |
|
163 { |
|
164 __SQLASSERT(aFullName.Length() > 0 && aFullName.Length() <= KMaxFileName, ESqlPanicBadArgument); |
|
165 __SQLASSERT(aConnFactoryL != NULL, ESqlPanicBadArgument); |
|
166 __SQLASSERT(!iConnection, ESqlPanicInternalError); |
|
167 |
|
168 __SQLLEAVE_IF_ERROR(iFullName.Create(aFullName)); |
|
169 |
|
170 //The second parameter of TSqlFreePageCallback's constructor is expected the be threshold in pages. |
|
171 //But the connection is not established yet and the page size is not known. Hence the threshold parameter |
|
172 //value is initialized with the threshold in Kbs. The connection construction is expected to convert |
|
173 //the threshold from Kbs to pages when the connection with the database is established. |
|
174 TSqlFreePageCallback callback(this, iSettings.iFreePageThresholdKb, &CSqlCompactEntry::FreePageCallback); |
|
175 iConnection = (*aConnFactoryL)(aFullName, callback); |
|
176 __SQLASSERT(iConnection != NULL, ESqlPanicInternalError); |
|
177 |
|
178 //"callback.iThreshold > 0" is an indication that the background compaction should be kicked-off |
|
179 if(callback.iThreshold > 0) |
|
180 { |
|
181 //Kick-off the compaction timer, if the number of the free pages is above the threshold. |
|
182 CSqlCompactEntry::FreePageCallback(this, callback.iThreshold); |
|
183 } |
|
184 |
|
185 SQLCOMPACTENTRY_INVARIANT(); |
|
186 } |
|
187 |
|
188 /** |
|
189 Performs a compaction step on the database. |
|
190 If the number of the free pages is bigger than the number of pages removed in one compaction step, |
|
191 the function will reschedule itself for another compaction step. |
|
192 |
|
193 @return KErrNoMemory, an out of memory condition has occurred; |
|
194 Note that the function may also return some other database specific |
|
195 errors categorised as ESqlDbError, and other system-wide error codes. |
|
196 |
|
197 @panic SqlDb 7 In _DEBUG mode. iPageCount <= 0 - no free pages to be processed. |
|
198 @panic SqlDb 7 In _DEBUG mode. iState != CSqlCompactEntry::EInProgress. |
|
199 */ |
|
200 TInt CSqlCompactEntry::Compact() |
|
201 { |
|
202 //RDebug::Print(_L("++ CSqlCompactEntry::Compact() ++\r\n")); |
|
203 SQLCOMPACTENTRY_INVARIANT(); |
|
204 __SQLASSERT(iPageCount > 0, ESqlPanicInternalError); |
|
205 __SQLASSERT(iState == CSqlCompactEntry::EInProgress, ESqlPanicInternalError); |
|
206 TInt processedPageCount = 0; |
|
207 iFreePageCallbackDisabled = ETrue; |
|
208 TInt err = Connection().Compact(iPageCount, processedPageCount, iSettings.iStepLength); |
|
209 iFreePageCallbackDisabled = EFalse; |
|
210 __SQLASSERT(processedPageCount >= 0, ESqlPanicInternalError); |
|
211 if(err == KErrNone) |
|
212 { |
|
213 if(processedPageCount > 0) |
|
214 { |
|
215 iPageCount -= processedPageCount; |
|
216 } |
|
217 else |
|
218 { |
|
219 iPageCount = 0; |
|
220 } |
|
221 __SQLASSERT(iPageCount >= 0, ESqlPanicInternalError); |
|
222 } |
|
223 if(iPageCount <= 0) |
|
224 {//No more pages to compact. Stop the compacting, move to EInactive state, remove from the timer queue. |
|
225 ResetState(); |
|
226 iTimer.DeQueue(*this); |
|
227 } |
|
228 SQLCOMPACTENTRY_INVARIANT(); |
|
229 return err; |
|
230 } |
|
231 |
|
232 /** |
|
233 Returns the full database name, including the path. |
|
234 |
|
235 @return Full database name. |
|
236 */ |
|
237 const TDesC& CSqlCompactEntry::FullName() const |
|
238 { |
|
239 SQLCOMPACTENTRY_INVARIANT(); |
|
240 return iFullName; |
|
241 } |
|
242 |
|
243 /** |
|
244 Resets the CSqlCompactEntry internal state. |
|
245 That means - (1) no scheduled compaction step and (2) no pending free pages to be removed. |
|
246 */ |
|
247 void CSqlCompactEntry::ResetState() |
|
248 { |
|
249 SQLCOMPACTENTRY_INVARIANT(); |
|
250 iState = CSqlCompactEntry::EInactive; |
|
251 iPageCount = 0; |
|
252 SQLCOMPACTENTRY_INVARIANT(); |
|
253 } |
|
254 |
|
255 /** |
|
256 Returns a reference to the MSqlCompactConn interface. |
|
257 @return A reference to the MSqlCompactConn interface. |
|
258 |
|
259 @panic SqlDb 7 NULL MSqlCompactConn interface. |
|
260 */ |
|
261 MSqlCompactConn& CSqlCompactEntry::Connection() |
|
262 { |
|
263 SQLCOMPACTENTRY_INVARIANT(); |
|
264 __SQLASSERT_ALWAYS(iConnection != NULL, ESqlPanicInternalError); |
|
265 return *iConnection; |
|
266 } |
|
267 |
|
268 #ifdef _DEBUG |
|
269 /** |
|
270 CSqlCompactEntry invariant. |
|
271 */ |
|
272 void CSqlCompactEntry::Invariant() const |
|
273 { |
|
274 __SQLASSERT(iFullName.Length() > 0 && iFullName.Length() <= KMaxFileName, ESqlPanicInternalError); |
|
275 __SQLASSERT(iConnection != NULL, ESqlPanicInternalError); |
|
276 __SQLASSERT(iRefCounter > 0, ESqlPanicInternalError); |
|
277 __SQLASSERT(iState == CSqlCompactEntry::EInactive || iState == CSqlCompactEntry::EInProgress, ESqlPanicInternalError); |
|
278 __SQLASSERT(iPageCount >= 0, ESqlPanicInternalError); |
|
279 iSettings.Invariant(); |
|
280 } |
|
281 #endif//_DEBUG |