|
1 // Copyright (c) 2006-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 // This file holds the class methods for the Rom Address Lookup Cache feature |
|
15 // of FBServ: CFbsRalCacheEl, CFbsRalCache. |
|
16 // |
|
17 // |
|
18 |
|
19 #include "FbsRalc.h" |
|
20 #include <e32svr.h> |
|
21 |
|
22 |
|
23 // ============================================================================ |
|
24 |
|
25 /** |
|
26 Destructor of CFbsRalCacheEl objects releasing memory used by attributes. |
|
27 @internalComponent |
|
28 @post Object state undefined. |
|
29 */ |
|
30 CFbsRalCacheEl::~CFbsRalCacheEl() |
|
31 { |
|
32 User::Free(iFilename); |
|
33 iFilename = 0; |
|
34 } |
|
35 |
|
36 /** |
|
37 Default constructor for CFbsRalCacheEl objects. |
|
38 @internalComponent |
|
39 @post CFbsRalCacheEl initialised with a null mapping information. |
|
40 */ |
|
41 CFbsRalCacheEl::CFbsRalCacheEl() |
|
42 : CBase(), iFilename(0), iAddress(0) |
|
43 { |
|
44 } |
|
45 |
|
46 /** |
|
47 Constructor for constructing TFbsRalCacheEl objects with valid |
|
48 mapping information. |
|
49 @internalComponent |
|
50 @param aFilename full name of the file to store |
|
51 @param aMemAddr ROM memory address file starts at |
|
52 @post TFbsRalCacheEl initialised with the filename and memory address |
|
53 supplied. |
|
54 @panic EEmptyFilename panic generated when no chars in name |
|
55 @panic EInvalidRomAddress panic generated when address out of range |
|
56 */ |
|
57 CFbsRalCacheEl* |
|
58 CFbsRalCacheEl::New( |
|
59 const TDesC& aFilename, |
|
60 TAny* aMemAddr |
|
61 ) |
|
62 { |
|
63 // Allocate memory for new cache element object and construct. |
|
64 CFbsRalCacheEl* ptr = new CFbsRalCacheEl; |
|
65 if (!ptr) |
|
66 return 0; |
|
67 |
|
68 // Initialise attributes of cache element. |
|
69 ptr->iFilename = HBufC::New(aFilename.Length()); |
|
70 if (!ptr->iFilename) |
|
71 { |
|
72 User::Free(ptr); |
|
73 return 0; |
|
74 } |
|
75 *(ptr->iFilename) = aFilename; |
|
76 ptr->iAddress = aMemAddr; |
|
77 #ifdef _RALC_DEBUG |
|
78 ptr->iHitCount = 1; |
|
79 #endif //_RALC_DEBUG |
|
80 |
|
81 // Done, return address to caller. |
|
82 return ptr; |
|
83 } |
|
84 |
|
85 /** |
|
86 This routine is used by callers to release the memory directly used for the |
|
87 CFbsRalCacheEl object specified WITHOUT destroying the object first. Users |
|
88 wishing to destroy the object can do so by calling the destructory directly. |
|
89 This is necessary since new/delete are not used for objects of this class as |
|
90 out of memory panics must be avoided. |
|
91 Therefore this routine must be used with caution to avoid memory leaks! |
|
92 @internalComponent |
|
93 @param aThisRef Ptr to object to free. Ptr set to 0 on exit |
|
94 */ |
|
95 void |
|
96 CFbsRalCacheEl::FreeOnly( |
|
97 CFbsRalCacheEl*& aThisRef |
|
98 ) |
|
99 { |
|
100 User::Free (aThisRef); |
|
101 aThisRef = 0; |
|
102 } |
|
103 |
|
104 /** |
|
105 An optimised routine for checking the filename in the entry matches that |
|
106 supplied to the routine. It compares filenames in a right to left fashion |
|
107 since most differences in filenames are in the last 16 characters or so. |
|
108 ASCII characters are compared in a case insensitive fashion. |
|
109 @internalComponent |
|
110 @param aSearchKey filename to compare entry with |
|
111 @return ETrue if entry matches search key, EFalse otherwise. |
|
112 */ |
|
113 TBool |
|
114 CFbsRalCacheEl::MatchKey( |
|
115 const TDesC& aSearchKey |
|
116 ) |
|
117 { |
|
118 if (!iFilename) |
|
119 return EFalse; |
|
120 |
|
121 // Check both filename descriptors are the same length |
|
122 TInt charIndex = iFilename->Length(); |
|
123 if (charIndex != aSearchKey.Length()) |
|
124 return EFalse; |
|
125 |
|
126 // Then check every character is the same by comparing right to left. |
|
127 while (charIndex) |
|
128 { |
|
129 charIndex--; |
|
130 if (ToLower((*iFilename)[charIndex]) != ToLower(aSearchKey[charIndex])) |
|
131 return EFalse; |
|
132 } |
|
133 |
|
134 // If we reach here we know the entry matches what we are looking for. |
|
135 return ETrue; |
|
136 } |
|
137 |
|
138 TInt CFbsRalCacheEl::ToLower(TInt aInt) |
|
139 { |
|
140 return (0x40 < aInt && 0x5B > aInt) ? (aInt + 0x20) : aInt; |
|
141 } |
|
142 |
|
143 // ============================================================================ |
|
144 |
|
145 /** |
|
146 Destructor of CFbsRalCache objects by resetting the circular buffer. |
|
147 @internalComponent |
|
148 @post Object state undefined. |
|
149 */ |
|
150 CFbsRalCache::~CFbsRalCache() |
|
151 { |
|
152 #ifdef _RALC_DEBUG |
|
153 RDebug::Print(_L("FBS RALCache destructed for process:%x\n"),(TUint)iProcId); |
|
154 PrintCache(); |
|
155 #endif //_RALC_DEBUG |
|
156 |
|
157 while (Count()) |
|
158 DropItem(); |
|
159 |
|
160 Reset(); |
|
161 } |
|
162 |
|
163 /** |
|
164 CFbsRalCache private constructor. |
|
165 @internalComponent |
|
166 @param aFs valid file serve session handle used in lookups. |
|
167 @post TFbsRalCache initialised with empty cache buffer. |
|
168 @see Public construction achieved using static New() class method. |
|
169 */ |
|
170 CFbsRalCache::CFbsRalCache( |
|
171 RFs& aFs |
|
172 ) |
|
173 : CCirBuf<CFbsRalCacheEl>(), iFs(aFs) |
|
174 { |
|
175 #ifdef _RALC_DEBUG |
|
176 RProcess current; |
|
177 iProcId = current.Id(); |
|
178 RDebug::Print(_L("FBS RALCache constructed for process:%x\n"), |
|
179 (TUint)iProcId); |
|
180 #endif |
|
181 } |
|
182 |
|
183 /** |
|
184 CFbsRalCache public constructor. This method allocates memory for a new |
|
185 object on the default heap and initialises it with the supplied data. |
|
186 @internalComponent |
|
187 @param aCacheSize number (fixed) of entries in the cache. |
|
188 @param aFs valid file serve session handle used in lookups. |
|
189 @return Pointer to new object, otherwise 0 when error detected. |
|
190 @post TFbsRalCache initialised with empty cache buffer. |
|
191 */ |
|
192 CFbsRalCache* |
|
193 CFbsRalCache::New( |
|
194 TInt aCacheSize, |
|
195 RFs& aFs |
|
196 ) |
|
197 { |
|
198 if (aCacheSize == 0) |
|
199 return 0; |
|
200 |
|
201 // Allocate memory for new cache object |
|
202 // and call its constructor to initialise it. |
|
203 CFbsRalCache* ptr = new CFbsRalCache(aFs); |
|
204 if (!ptr) |
|
205 return 0; |
|
206 |
|
207 // Reserve capacity in circular buffer for cache entries. |
|
208 TRAPD(lc, ptr->SetLengthL(aCacheSize)); |
|
209 if (lc != KErrNone) |
|
210 { |
|
211 User::Free(ptr); |
|
212 return 0; |
|
213 } |
|
214 |
|
215 // Successful, new cache created. |
|
216 return ptr; |
|
217 } |
|
218 |
|
219 /** |
|
220 This is the main cache lookup method for getting a file's start address |
|
221 should it be found in ROM. It first scans the cache for a match and on a hit |
|
222 it returns the stored address. On a miss it uses the file server to get |
|
223 the file's ROM address. This result if +ve is stored and the Most-recently-used |
|
224 cache, otherwise 0 is returned. |
|
225 @internalComponent |
|
226 @param aFileKey Full file name of file to get address for. |
|
227 @return Start address in ROM for the file, 0 if not in ROM. |
|
228 @post Cache updated with new entry if ROM file and not in cache. |
|
229 */ |
|
230 TAny* |
|
231 CFbsRalCache::Lookup( |
|
232 const TDesC& aFileKey |
|
233 ) |
|
234 { |
|
235 |
|
236 // Search the cache from the head to the tail should it have any entries |
|
237 // based on a MRU policy. |
|
238 if (Count()) |
|
239 { |
|
240 TUint8* ptr = iHead; |
|
241 for (TInt num = Count(); num; num--) |
|
242 { |
|
243 // Calculate the address of the entry. |
|
244 if (ptr <= iPtr) |
|
245 ptr = iPtrE; |
|
246 ptr-=iSize; |
|
247 CFbsRalCacheEl* entry = (CFbsRalCacheEl*)ptr; |
|
248 |
|
249 // Compare the entry key with that suppled for a match and return. |
|
250 if (entry->MatchKey(aFileKey)) |
|
251 { |
|
252 #ifdef _RALC_DEBUG |
|
253 RDebug::Print(_L("FBS RALCache lookup HIT: %S\n"), &aFileKey); |
|
254 entry->iHitCount++; |
|
255 #endif //_RALC_DEBUG |
|
256 return entry->iAddress; |
|
257 } |
|
258 } |
|
259 } |
|
260 |
|
261 #ifdef _RALC_DEBUG |
|
262 RDebug::Print(_L("FBS RALCache lookup MISS: %S\n"), &aFileKey); |
|
263 #endif //_RALC_DEBUG |
|
264 |
|
265 // Filename not in cache, ask file server for it's ROM address. |
|
266 TAny *romAddr = iFs.IsFileInRom (aFileKey); |
|
267 if (romAddr) |
|
268 { |
|
269 // Store new filename/address mapping in cache and return. |
|
270 (void)AddItem (aFileKey, romAddr); |
|
271 return romAddr; |
|
272 } |
|
273 |
|
274 // It's not a file in ROM |
|
275 return 0; |
|
276 } |
|
277 |
|
278 /** |
|
279 This method will create a cache entry from the supplied data and add it to the |
|
280 head of the circular cache buffer. If the cache is full this will result in the |
|
281 entry at the tail being overwritten with the new entry inserted at the head. |
|
282 @internalComponent |
|
283 @param aFilename full name of the file to store |
|
284 @param aMemAddr ROM memory address file starts at |
|
285 @return ETrue when successfully added, EFalse otherwise. |
|
286 @post Cache updated as described above. |
|
287 */ |
|
288 TBool |
|
289 CFbsRalCache::AddItem( |
|
290 const TDesC& aFilename, |
|
291 TAny* aMemAddr |
|
292 ) |
|
293 { |
|
294 // Construct the new cache entry from the supplied data. |
|
295 CFbsRalCacheEl* entry = CFbsRalCacheEl::New(aFilename, aMemAddr); |
|
296 if (!entry) |
|
297 return EFalse; |
|
298 |
|
299 // Make room in the cache if we need to based on MRU policy. |
|
300 if (Count() == Length()) // Is it full? |
|
301 DropItem(); |
|
302 |
|
303 // Add a copy of the cache entry to the circular buffer. |
|
304 if (Add(entry) == 0) |
|
305 { |
|
306 // Failed, can't cache it! |
|
307 entry->~CFbsRalCacheEl(); |
|
308 CFbsRalCacheEl::FreeOnly(entry); |
|
309 return EFalse; |
|
310 } |
|
311 |
|
312 // Item now cached so clean up local entry memory only |
|
313 CFbsRalCacheEl::FreeOnly(entry); |
|
314 return ETrue; |
|
315 } |
|
316 |
|
317 /** |
|
318 This method will create a cache entry from the supplied data and add it to the |
|
319 head of the circular cache buffer. If tha cache is full this will result in the |
|
320 entry at the tail being overwritten with the new entry inserted at the head. |
|
321 @internalComponent |
|
322 @post Cache updated as described above. |
|
323 */ |
|
324 void |
|
325 CFbsRalCache::DropItem() |
|
326 { |
|
327 // No items to drop from cache!? |
|
328 if (Count() == 0) |
|
329 return; |
|
330 |
|
331 // Remove cache entry at tail copying into temporary variable. |
|
332 CFbsRalCacheEl entry; |
|
333 Remove(&entry); |
|
334 |
|
335 #ifdef _RALC_DEBUG |
|
336 RDebug::Print(_L("FBS RALCache droped element: %S, %x, %d\n"), |
|
337 entry.iFilename, entry.iAddress, entry.iHitCount); |
|
338 #endif //_RALC_DEBUG |
|
339 |
|
340 // 'entry' destroyed on exit and cleaned up. |
|
341 } |
|
342 |
|
343 |
|
344 #ifdef _RALC_DEBUG |
|
345 void |
|
346 CFbsRalCache::PrintCache() |
|
347 { |
|
348 if (Count()) |
|
349 { |
|
350 TUint8* ptr = iHead; |
|
351 TInt num = Count(); |
|
352 RDebug::Print(_L("FBS RALCache contents (%d):\n"), num); |
|
353 for (; num; num--) |
|
354 { |
|
355 if (ptr <= iPtr) |
|
356 ptr = iPtrE; |
|
357 ptr-=iSize; |
|
358 CFbsRalCacheEl* entry = (CFbsRalCacheEl*)ptr; |
|
359 RDebug::Print(_L("FBS RALCache El %d: %S, %x, %d\n"), num, |
|
360 entry->iFilename, entry->iAddress, entry->iHitCount); |
|
361 } |
|
362 } |
|
363 else |
|
364 { |
|
365 RDebug::Print(_L("FBS RALCache emtpy.\n")); |
|
366 } |
|
367 } |
|
368 #endif |
|
369 |
|
370 // ========================================================================== |