18 #include <e32test.h> |
18 #include <e32test.h> |
19 #include <e32math.h> |
19 #include <e32math.h> |
20 #include <e32svr.h> |
20 #include <e32svr.h> |
21 #include <hal.h> |
21 #include <hal.h> |
22 #include <d32dbmsconstants.h> |
22 #include <d32dbmsconstants.h> |
23 |
23 #include "t_dbcmdlineutil.h" |
24 // MSVC++ up to 5.0 has problems with expanding inline functions |
24 |
25 // This disables the mad warnings for the whole project |
25 TCmdLineParams TheCmdLineParams; |
26 #if defined(NDEBUG) && defined(__VC32__) && _MSC_VER<=1100 |
26 TFileName TheDbFileName; |
27 #pragma warning(disable : 4710) // function not expanded. MSVC 5.0 is stupid |
27 RFile TheLogFile; |
28 #endif |
28 RTest TheTest(_L("t_dbbench")); |
29 |
29 RDbNamedDatabase TheDatabase; |
30 class TTimer |
30 RDbView TheView; |
31 { |
31 RFs TheFs; |
32 public: |
32 |
33 void Start(); |
33 TBuf<250> TheLogLine; |
34 TReal Stop() const; |
34 TBuf8<250> TheLogLine8; |
35 private: |
35 |
36 TUint iTicks; |
|
37 }; |
|
38 |
|
39 LOCAL_D RTest test(_L("t_dbbench")); |
|
40 LOCAL_D CTrapCleanup* TheTrapCleanup; |
|
41 LOCAL_D RDbNamedDatabase TheDatabase; |
|
42 LOCAL_D RDbView TheView; |
|
43 LOCAL_D RFs TheFs; |
|
44 |
|
45 const TInt KTestCleanupStack=0x20; |
|
46 //T_BENCH file shall not be deleted at the end of the test! It will be used by T_COMP test. |
|
47 const TPtrC KTestDatabase=_S("\\DBMS-TST\\T_BENCH.DB"); |
|
48 const TPtrC KTableName=_S("Test"); |
36 const TPtrC KTableName=_S("Test"); |
49 const TPtrC KColCluster=_S("Cluster"); |
37 const TPtrC KColCluster=_S("Cluster"); |
50 const TPtrC KColXcluster=_S("xCluster"); |
38 const TPtrC KColXcluster=_S("xCluster"); |
51 const TPtrC KColRandom=_S("Random"); |
39 const TPtrC KColRandom=_S("Random"); |
52 const TPtrC KColXrandom=_S("xRandom"); |
40 const TPtrC KColXrandom=_S("xRandom"); |
53 const TInt KRecords=2000; |
41 const TInt KRecords=2000; |
54 |
|
55 static TTimer TheTimer; |
|
56 |
|
57 void TTimer::Start() |
|
58 { |
|
59 iTicks=User::FastCounter(); |
|
60 } |
|
61 |
|
62 TReal TTimer::Stop() const |
|
63 { |
|
64 TUint ticks = User::FastCounter() - iTicks; |
|
65 TInt freq = 0; |
|
66 test(HAL::Get(HAL::EFastCounterFrequency, freq) == KErrNone); |
|
67 const TInt KMicroSecIn1Sec = 1000000; |
|
68 const TInt KMsIn1Sec = 1000; |
|
69 double v = ((double)ticks * KMicroSecIn1Sec) / (double)freq; TInt v2 = (TInt)v; |
|
70 return v2 / KMsIn1Sec; |
|
71 } |
|
72 |
|
73 LOCAL_C void CloseDatabase() |
|
74 { |
|
75 TheDatabase.Close(); |
|
76 } |
|
77 |
|
78 /** |
|
79 Create the database: keep the code 050 compatible |
|
80 |
|
81 @SYMTestCaseID SYSLIB-DBMS-CT-0577 |
|
82 @SYMTestCaseDesc Benchmark Tests. Creation of a local Database test |
|
83 @SYMTestPriority Medium |
|
84 @SYMTestActions Attempt to test RDbNamedDatabase::CreateTable(),RDbNamedDatabase::CreateIndex(), |
|
85 RDbNamedDatabase::Compact(),RDbView::Prepare() functions |
|
86 @SYMTestExpectedResults Test must not fail |
|
87 @SYMREQ REQ0000 |
|
88 */ |
|
89 LOCAL_C void CreateDatabaseL() |
|
90 { |
|
91 test.Next(_L(" @SYMTestCaseID:SYSLIB-DBMS-CT-0577 ")); |
|
92 User::LeaveIfError(TheDatabase.Replace(TheFs,KTestDatabase)); |
|
93 CDbColSet& set=*CDbColSet::NewLC(); |
|
94 TDbCol col(KColCluster,EDbColInt32); |
|
95 col.iAttributes=col.ENotNull; |
|
96 set.AddL(col); |
|
97 col.iName=KColXcluster; |
|
98 set.AddL(col); |
|
99 col.iName=KColRandom; |
|
100 set.AddL(col); |
|
101 col.iName=KColXrandom; |
|
102 set.AddL(col); |
|
103 TInt r=TheDatabase.CreateTable(KTableName,set); |
|
104 test (r==KErrNone); |
|
105 CleanupStack::PopAndDestroy(); |
|
106 TheTimer.Start(); |
|
107 r=TheView.Prepare(TheDatabase,_L("select * from test"),TheView.EInsertOnly); |
|
108 TheDatabase.Begin(); |
|
109 test (r==KErrNone); |
|
110 TInt jj=0; |
|
111 for (TInt ii=0;ii<KRecords;++ii) |
|
112 { |
|
113 TheView.InsertL(); |
|
114 jj=(jj+23); |
|
115 if (jj>=KRecords) |
|
116 jj-=KRecords; |
|
117 TheView.SetColL(1,ii); |
|
118 TheView.SetColL(2,ii); |
|
119 TheView.SetColL(3,jj); |
|
120 TheView.SetColL(4,jj); |
|
121 TheView.PutL(); |
|
122 } |
|
123 r=TheDatabase.Commit(); |
|
124 test (r==KErrNone); |
|
125 TheView.Close(); |
|
126 test.Printf(_L("Build table: %7.1f ms\n"),TheTimer.Stop()); |
|
127 TheTimer.Start(); |
|
128 CDbKey& key=*CDbKey::NewLC(); |
|
129 key.AddL(KColXcluster); |
|
130 key.MakeUnique(); |
|
131 r=TheDatabase.CreateIndex(KColXcluster,KTableName,key); |
|
132 test (r==KErrNone); |
|
133 test.Printf(_L("Cluster index: %7.1f ms\n"),TheTimer.Stop()); |
|
134 TheTimer.Start(); |
|
135 key.Clear(); |
|
136 key.AddL(KColXrandom); |
|
137 r=TheDatabase.CreateIndex(KColXrandom,KTableName,key); |
|
138 test (r==KErrNone); |
|
139 CleanupStack::PopAndDestroy(); |
|
140 test.Printf(_L("Random index: %7.1f ms\n"),TheTimer.Stop()); |
|
141 TheTimer.Start(); |
|
142 r = TheDatabase.Compact(); |
|
143 test.Printf(_L("Compact: %7.1f ms\n"),TheTimer.Stop()); |
|
144 test (r == KErrNone); |
|
145 } |
|
146 |
|
147 LOCAL_C TReal Evaluate(const TDesC& aSql) |
|
148 { |
|
149 TInt m=1; |
|
150 for (;;) |
|
151 { |
|
152 TheTimer.Start(); |
|
153 for (TInt ii=0;ii<m;++ii) |
|
154 { |
|
155 TInt r=TheView.Prepare(TheDatabase,aSql,KDbUnlimitedWindow,TheView.EReadOnly); |
|
156 if (r<0) |
|
157 return r; |
|
158 r=TheView.EvaluateAll(); |
|
159 test (r==KErrNone); |
|
160 TheView.Close(); |
|
161 } |
|
162 TReal t=TheTimer.Stop(); |
|
163 if (t>=100.0) |
|
164 return t/m; |
|
165 m*=4; |
|
166 } |
|
167 } |
|
168 |
42 |
169 struct TTest |
43 struct TTest |
170 { |
44 { |
171 const TText* iName; |
45 const TText* iName; |
172 const TText* iQuery; |
46 const TText* iQuery; |
173 }; |
47 }; |
|
48 |
174 const TTest KQuery[]= |
49 const TTest KQuery[]= |
175 { |
50 { |
176 {_S("project"),_S("select cluster,xcluster,random,xrandom from test")}, |
51 {_S("project"),_S("select cluster,xcluster,random,xrandom from test")}, |
177 {_S("restrict 1"),_S("select * from test where cluster=0")}, |
52 {_S("restrict 1"),_S("select * from test where cluster=0")}, |
178 {_S("restrict 2"),_S("select * from test where xrandom=0")}, |
53 {_S("restrict 2"),_S("select * from test where xrandom=0")}, |
183 {_S("all 2"),_S("select * from test where xcluster<500 order by xrandom")}, |
58 {_S("all 2"),_S("select * from test where xcluster<500 order by xrandom")}, |
184 {_S("all 3"),_S("select * from test where xcluster<500 order by xcluster")}, |
59 {_S("all 3"),_S("select * from test where xcluster<500 order by xcluster")}, |
185 {_S("all 4"),_S("select * from test where xcluster<500 and xrandom<200 order by xcluster")} |
60 {_S("all 4"),_S("select * from test where xcluster<500 and xrandom<200 order by xcluster")} |
186 }; |
61 }; |
187 |
62 |
|
63 /////////////////////////////////////////////////////////////////////////////////////// |
|
64 |
|
65 void TestEnvDestroy() |
|
66 { |
|
67 TheView.Close(); |
|
68 TheDatabase.Close(); |
|
69 if(TheCmdLineParams.iLogFileName.Length() > 0) |
|
70 { |
|
71 (void)TheLogFile.Flush(); |
|
72 TheLogFile.Close(); |
|
73 } |
|
74 //T_BENCH.DB cannot be deleted here, because it is used by T_DBCOMP test! |
|
75 TheFs.Close(); |
|
76 } |
|
77 |
|
78 /////////////////////////////////////////////////////////////////////////////////////// |
|
79 //Test macros and functions |
|
80 void Check1(TInt aValue, TInt aLine) |
|
81 { |
|
82 if(!aValue) |
|
83 { |
|
84 TestEnvDestroy(); |
|
85 TheTest.Printf(_L("*** Line %d. Expression evaluated to false\r\n"), aLine); |
|
86 TheTest(EFalse, aLine); |
|
87 } |
|
88 } |
|
89 void Check2(TInt aValue, TInt aExpected, TInt aLine) |
|
90 { |
|
91 if(aValue != aExpected) |
|
92 { |
|
93 TestEnvDestroy(); |
|
94 TheTest.Printf(_L("*** Line %d, Expected error: %d, got: %d\r\n"), aLine, aExpected, aValue); |
|
95 TheTest(EFalse, aLine); |
|
96 } |
|
97 } |
|
98 #define TEST(arg) ::Check1((arg), __LINE__) |
|
99 #define TEST2(aValue, aExpected) ::Check2(aValue, aExpected, __LINE__) |
|
100 |
|
101 /////////////////////////////////////////////////////////////////////////////////////// |
|
102 |
|
103 TInt FastCounterFrequency() |
|
104 { |
|
105 static TInt freq = 0; |
|
106 if(freq == 0) |
|
107 { |
|
108 TEST2(HAL::Get(HAL::EFastCounterFrequency, freq), KErrNone); |
|
109 } |
|
110 return freq; |
|
111 } |
|
112 |
|
113 //Prints the test case title and execution time in microseconds |
|
114 void PrintResult(const TDesC& aTitle, TUint32 aStartTicks, TUint32 aEndTicks, TInt aIterations = 0) |
|
115 { |
|
116 TInt freq = FastCounterFrequency(); |
|
117 TInt64 diffTicks = (TInt64)aEndTicks - (TInt64)aStartTicks; |
|
118 if(diffTicks < 0) |
|
119 { |
|
120 diffTicks = KMaxTUint32 + diffTicks + 1; |
|
121 } |
|
122 const TInt KMicroSecIn1Sec = 1000000; |
|
123 TInt32 us = (diffTicks * KMicroSecIn1Sec) / freq; |
|
124 if(aIterations > 0) |
|
125 { |
|
126 us /= aIterations; |
|
127 } |
|
128 TheTest.Printf(_L("%S: %d us\r\n"), &aTitle, us); |
|
129 if(TheCmdLineParams.iLogFileName.Length() > 0) |
|
130 { |
|
131 TheLogLine.Format(_L("%S¬%d¬us\r\n"), &aTitle, us); |
|
132 TheLogLine8.Copy(TheLogLine); |
|
133 (void)TheLogFile.Write(TheLogLine8); |
|
134 } |
|
135 } |
|
136 |
|
137 //Calculates time in microseconds |
|
138 TInt CalcTime(TUint32 aStartTicks, TUint32 aEndTicks) |
|
139 { |
|
140 TInt freq = FastCounterFrequency(); |
|
141 TInt64 diffTicks = (TInt64)aEndTicks - (TInt64)aStartTicks; |
|
142 if(diffTicks < 0) |
|
143 { |
|
144 diffTicks = KMaxTUint32 + diffTicks + 1; |
|
145 } |
|
146 const TInt KMicroSecIn1Sec = 1000000; |
|
147 TInt32 us = (diffTicks * KMicroSecIn1Sec) / freq; |
|
148 return us; |
|
149 } |
|
150 |
|
151 /////////////////////////////////////////////////////////////////////////////////////// |
|
152 |
|
153 /** |
|
154 Create the database: keep the code 050 compatible |
|
155 |
|
156 @SYMTestCaseID SYSLIB-DBMS-CT-0577 |
|
157 @SYMTestCaseDesc Benchmark Tests. Creation of a local Database test |
|
158 @SYMTestPriority Medium |
|
159 @SYMTestActions Attempt to test RDbNamedDatabase::CreateTable(),RDbNamedDatabase::CreateIndex(), |
|
160 RDbNamedDatabase::Compact(),RDbView::Prepare() functions |
|
161 @SYMTestExpectedResults Test must not fail |
|
162 @SYMREQ REQ0000 |
|
163 */ |
|
164 void CreateDatabaseL() |
|
165 { |
|
166 TInt err = TheDatabase.Replace(TheFs, TheDbFileName); |
|
167 TEST2(err, KErrNone); |
|
168 |
|
169 CDbColSet* set = CDbColSet::NewLC(); |
|
170 TDbCol col(KColCluster,EDbColInt32); |
|
171 col.iAttributes=col.ENotNull; |
|
172 set->AddL(col); |
|
173 col.iName=KColXcluster; |
|
174 set->AddL(col); |
|
175 col.iName=KColRandom; |
|
176 set->AddL(col); |
|
177 col.iName=KColXrandom; |
|
178 set->AddL(col); |
|
179 |
|
180 err = TheDatabase.CreateTable(KTableName, *set); |
|
181 TEST2(err, KErrNone); |
|
182 CleanupStack::PopAndDestroy(set); |
|
183 |
|
184 TUint32 ticksStart = User::FastCounter(); |
|
185 err = TheView.Prepare(TheDatabase,_L("select * from test"),TheView.EInsertOnly); |
|
186 TEST2(err, KErrNone); |
|
187 TheDatabase.Begin(); |
|
188 TInt jj=0; |
|
189 for (TInt ii=0;ii<KRecords;++ii) |
|
190 { |
|
191 TheView.InsertL(); |
|
192 jj=(jj+23); |
|
193 if (jj>=KRecords) |
|
194 jj-=KRecords; |
|
195 TheView.SetColL(1,ii); |
|
196 TheView.SetColL(2,ii); |
|
197 TheView.SetColL(3,jj); |
|
198 TheView.SetColL(4,jj); |
|
199 TheView.PutL(); |
|
200 } |
|
201 err = TheDatabase.Commit(); |
|
202 TEST2(err, KErrNone); |
|
203 TheView.Close(); |
|
204 TUint32 ticksEnd = User::FastCounter(); |
|
205 PrintResult(_L("Build table"), ticksStart, ticksEnd); |
|
206 |
|
207 ticksStart = User::FastCounter(); |
|
208 CDbKey* key = CDbKey::NewLC(); |
|
209 key->AddL(KColXcluster); |
|
210 key->MakeUnique(); |
|
211 err = TheDatabase.CreateIndex(KColXcluster,KTableName,*key); |
|
212 TEST2(err, KErrNone); |
|
213 ticksEnd = User::FastCounter(); |
|
214 PrintResult(_L("Cluster index"), ticksStart, ticksEnd); |
|
215 |
|
216 ticksStart = User::FastCounter(); |
|
217 key->Clear(); |
|
218 key->AddL(KColXrandom); |
|
219 err = TheDatabase.CreateIndex(KColXrandom,KTableName,*key); |
|
220 TEST2(err, KErrNone); |
|
221 CleanupStack::PopAndDestroy(key); |
|
222 ticksEnd = User::FastCounter(); |
|
223 PrintResult(_L("Random index"), ticksStart, ticksEnd); |
|
224 |
|
225 ticksStart = User::FastCounter(); |
|
226 err = TheDatabase.Compact(); |
|
227 ticksEnd = User::FastCounter(); |
|
228 PrintResult(_L("Compact"), ticksStart, ticksEnd); |
|
229 TEST2(err, KErrNone); |
|
230 } |
|
231 |
|
232 void Evaluate(const TDesC& aTitle, const TDesC& aSql) |
|
233 { |
|
234 TInt m = 1; |
|
235 for(;;) |
|
236 { |
|
237 TUint32 ticksStart = User::FastCounter(); |
|
238 for(TInt i=0; i<m; ++i) |
|
239 { |
|
240 TInt err = TheView.Prepare(TheDatabase,aSql,KDbUnlimitedWindow,TheView.EReadOnly); |
|
241 TEST2(err, KErrNone); |
|
242 err = TheView.EvaluateAll(); |
|
243 TEST2(err, KErrNone); |
|
244 TheView.Close(); |
|
245 } |
|
246 TUint32 ticksEnd = User::FastCounter(); |
|
247 TInt us = CalcTime(ticksStart, ticksEnd); |
|
248 if(us > 100000) |
|
249 { |
|
250 PrintResult(aTitle, ticksStart, ticksEnd, m); |
|
251 return; |
|
252 } |
|
253 m *= 4; |
|
254 } |
|
255 } |
|
256 |
188 /** |
257 /** |
189 @SYMTestCaseID SYSLIB-DBMS-CT-0578 |
258 @SYMTestCaseID SYSLIB-DBMS-CT-0578 |
190 @SYMTestCaseDesc Benchmark Test.Querying a local Database Test |
259 @SYMTestCaseDesc Benchmark Test.Querying a local Database Test |
191 @SYMTestPriority Medium |
260 @SYMTestPriority Medium |
192 @SYMTestActions Evaluate SELECT queries on the created database |
261 @SYMTestActions Evaluate SELECT queries on the created database |
193 @SYMTestExpectedResults Test must not fail |
262 @SYMTestExpectedResults Test must not fail |
194 @SYMREQ REQ0000 |
263 @SYMREQ REQ0000 |
195 */ |
264 */ |
196 LOCAL_C void Queries() |
265 void Queries() |
197 { |
266 { |
198 test.Next(_L(" @SYMTestCaseID:SYSLIB-DBMS-CT-0578 ")); |
267 for(TUint ii=0;ii<sizeof(KQuery)/sizeof(KQuery[0]);++ii) |
199 for (TUint ii=0;ii<sizeof(KQuery)/sizeof(KQuery[0]);++ii) |
268 { |
200 { |
269 Evaluate(TPtrC(KQuery[ii].iName), TPtrC(KQuery[ii].iQuery)); |
201 test.Printf(_L("%15s: "),KQuery[ii].iName); |
270 } |
202 TReal t=Evaluate(TPtrC(KQuery[ii].iQuery)); |
271 } |
203 if (t<0.0) |
272 |
204 test.Printf(_L("-\n")); |
273 void BenchTestL() |
205 else |
274 { |
206 test.Printf(_L("%7.1f ms\n"),t); |
275 TheTest.Start(_L("@SYMTestCaseID:SYSLIB-DBMS-CT-0577 RDbNamedDatabase performance test")); |
207 } |
|
208 } |
|
209 |
|
210 // |
|
211 // Benchmark tests |
|
212 // |
|
213 LOCAL_C void BenchTestL() |
|
214 { |
|
215 CreateDatabaseL(); |
276 CreateDatabaseL(); |
|
277 |
|
278 TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-DBMS-CT-0578 SQL queries performance test")); |
216 Queries(); |
279 Queries(); |
217 CloseDatabase(); |
280 |
218 } |
281 TheDatabase.Close(); |
219 |
282 } |
220 // |
283 |
221 // Prepare the test directory. |
284 void TestEnvInit() |
222 // |
|
223 LOCAL_C void setupTestDirectory() |
|
224 { |
285 { |
225 TInt r=TheFs.Connect(); |
286 TInt err = TheFs.Connect(); |
226 test(r==KErrNone); |
287 TEST2(err, KErrNone); |
227 // |
288 |
228 #if 0 |
289 err = TheFs.MkDirAll(TheDbFileName); |
229 TDriveList drives; |
290 TEST(err == KErrNone || err == KErrAlreadyExists); |
230 TheFs.DriveList(drives); |
291 |
231 if (drives[EDriveK] == KDriveAbsent) |
292 if(TheCmdLineParams.iLogFileName.Length() > 0) |
232 { |
293 { |
233 TInt r = TheFs.AddFileSystem(_L("ELFFS")); |
294 err = TheLogFile.Replace(TheFs, TheCmdLineParams.iLogFileName, EFileRead | EFileWrite); |
234 test (r == KErrNone); |
295 TEST2(err, KErrNone); |
235 r = TheFs.MountFileSystem(_L("Lffs"),EDriveK); |
296 LogConfig(TheLogFile, TheCmdLineParams); |
236 if (r == KErrCorrupt || r == KErrNotReady) |
297 } |
237 { |
298 } |
238 RFormat format; |
299 |
239 TInt count; |
300 TInt E32Main() |
240 r = format.Open(TheFs, _L("K:\\"), EHighDensity, count); |
|
241 test (r == KErrNone); |
|
242 while (count) |
|
243 format.Next(count); |
|
244 format.Close(); |
|
245 } |
|
246 else |
|
247 test (r == KErrNone); |
|
248 } |
|
249 #endif |
|
250 // |
|
251 r=TheFs.MkDir(KTestDatabase); |
|
252 test(r==KErrNone || r==KErrAlreadyExists); |
|
253 } |
|
254 |
|
255 // |
|
256 // Initialise the cleanup stack. |
|
257 // |
|
258 LOCAL_C void setupCleanup() |
|
259 { |
301 { |
260 TheTrapCleanup=CTrapCleanup::New(); |
302 TheTest.Title(); |
261 test(TheTrapCleanup!=NULL); |
303 |
262 TRAPD(r,\ |
304 CTrapCleanup* tc = CTrapCleanup::New(); |
263 {\ |
305 TheTest(tc != NULL); |
264 for (TInt i=KTestCleanupStack;i>0;i--)\ |
306 |
265 CleanupStack::PushL((TAny*)0);\ |
307 GetCmdLineParams(TheTest, _L("t_dbbench"), TheCmdLineParams); |
266 CleanupStack::Pop(KTestCleanupStack);\ |
308 _LIT(KDbName, "c:\\dbms-tst\\t_bench.db"); |
267 }); |
309 PrepareDbName(KDbName, TheCmdLineParams.iDriveName, TheDbFileName); |
268 test(r==KErrNone); |
310 TheTest.Printf(_L("==Database: %S\r\n"), &TheDbFileName); |
269 } |
311 |
270 |
|
271 // |
|
272 // entry point |
|
273 // |
|
274 GLDEF_C TInt E32Main() |
|
275 { |
|
276 test.Title(); |
|
277 setupTestDirectory(); |
|
278 setupCleanup(); |
|
279 __UHEAP_MARK; |
312 __UHEAP_MARK; |
280 // |
313 |
281 test.Start(_L("Benchmarking...")); |
314 TestEnvInit(); |
282 TRAPD(r,BenchTestL()); |
315 TRAPD(err, BenchTestL()); |
283 test(r==KErrNone); |
316 TEST2(err, KErrNone); |
284 test.End(); |
317 TestEnvDestroy(); |
285 // |
318 |
286 __UHEAP_MARKEND; |
319 __UHEAP_MARKEND; |
287 delete TheTrapCleanup; |
320 |
288 |
321 User::Heap().Check(); |
289 //T_BENCH.DB cannot be deleted here, because it is used by T_COMP test! |
322 |
290 |
323 TheTest.End(); |
291 TheFs.Close(); |
324 TheTest.Close(); |
292 test.Close(); |
325 |
293 return 0; |
326 delete tc; |
|
327 |
|
328 return KErrNone; |
294 } |
329 } |