192 // ----------------------------------------------------------------------------- |
192 // ----------------------------------------------------------------------------- |
193 // |
193 // |
194 void CSegmentedHeapBuffer::AppendL(TInt& aRemainder, const TDesC8& aDes) |
194 void CSegmentedHeapBuffer::AppendL(TInt& aRemainder, const TDesC8& aDes) |
195 { |
195 { |
196 aRemainder = aDes.Length(); // consumed nothing yet. |
196 aRemainder = aDes.Length(); // consumed nothing yet. |
197 TInt workingLen; |
|
198 TInt workingOffset=0; // read position in source descriptor |
|
199 HBufC8* currentBuffer; |
197 HBufC8* currentBuffer; |
200 |
198 |
|
199 // 90% of cached objects are less than 4KB. |
|
200 // Lots of them also come in two parts from the http stack. |
|
201 #define HTTPSEGMENTEDBUFFER_OPTION_INCREMENT_GRADUALLY |
|
202 #ifndef HTTPSEGMENTEDBUFFER_OPTION_INCREMENT_GRADUALLY |
201 TInt lastBuffer = iBufferList.Count()-1; |
203 TInt lastBuffer = iBufferList.Count()-1; |
202 if ( lastBuffer < 0 ) |
204 if ( lastBuffer < 0 ) |
203 { |
205 { |
204 // TODO: Make the first block only equal to the size of data we need? |
206 // TODO: Make the first block only equal to the size of data we need? |
205 // Take some traces to see what happens. |
207 // Take some traces to see what happens. |
206 |
|
207 // no blocks allocated. May leave here if we can't get space. |
208 // no blocks allocated. May leave here if we can't get space. |
208 currentBuffer = HBufC8::NewLC(iBufferSize); |
209 currentBuffer = HBufC8::NewLC(iBufferSize); |
209 iBufferList.AppendL(currentBuffer); |
210 iBufferList.AppendL(currentBuffer); |
210 CleanupStack::Pop(currentBuffer); |
211 CleanupStack::Pop(currentBuffer); |
211 lastBuffer = 0; |
212 lastBuffer = 0; |
234 currentBuffer = HBufC8::NewLC(iBufferSize); |
237 currentBuffer = HBufC8::NewLC(iBufferSize); |
235 iBufferList.AppendL(currentBuffer); |
238 iBufferList.AppendL(currentBuffer); |
236 CleanupStack::Pop(currentBuffer); |
239 CleanupStack::Pop(currentBuffer); |
237 } |
240 } |
238 } |
241 } |
|
242 #else |
|
243 #ifdef __CACHELOG__ |
|
244 HttpCacheUtil::WriteFormatLog(0, _L("CHttpCacheSegmentedBuffer::AppendL %08x adding %d bytes to %d"), this, aRemainder, this->Length()); |
|
245 #endif |
|
246 // because most items are small, increment buffers up to the configured segment size as data is added... |
|
247 TInt workingOffset = 0; |
|
248 TInt lastBuffer = iBufferList.Count()-1; |
|
249 if ( lastBuffer < 0 ) |
|
250 { |
|
251 // special case for first allocation. |
|
252 // no blocks allocated. May leave here if we can't get space. |
|
253 if( aRemainder <= iBufferSize) // we can fit the first block into a single segment |
|
254 { |
|
255 #ifdef __CACHELOG__ |
|
256 HttpCacheUtil::WriteFormatLog(0, _L(" First alloc %d into buffer fits inside %d"), aRemainder, iBufferSize ); |
|
257 #endif |
|
258 // fast path optimisation for first alloc into an empty segmented buffer. |
|
259 currentBuffer = aDes.AllocLC(); |
|
260 iBufferList.AppendL( currentBuffer ); |
|
261 CleanupStack::Pop( currentBuffer ); |
|
262 aRemainder = 0; |
|
263 } |
|
264 else |
|
265 { |
|
266 // the segmented buffer is empty and the first block to add is bigger than the configured block size |
|
267 // fill the first segment and leave the rest for the loop |
|
268 #ifdef __CACHELOG__ |
|
269 HttpCacheUtil::WriteFormatLog(0, _L(" First alloc %d is bigger than %d"), aRemainder, iBufferSize ); |
|
270 #endif |
|
271 currentBuffer = HBufC8::NewLC( iBufferSize ); |
|
272 iBufferList.AppendL( currentBuffer ); |
|
273 CleanupStack::Pop( currentBuffer ); |
|
274 currentBuffer->Des().Copy( aDes.Ptr(), iBufferSize ); |
|
275 workingOffset = iBufferSize; // when we add the remaining data, we start from here. |
|
276 aRemainder -= iBufferSize; |
|
277 } |
|
278 } |
|
279 else |
|
280 { |
|
281 #ifdef __CACHELOG__ |
|
282 HttpCacheUtil::WriteFormatLog(0, _L(" Buffer already contains data")); |
|
283 #endif |
|
284 currentBuffer = iBufferList[lastBuffer]; |
|
285 } |
|
286 |
|
287 // When we get to here the following state applies. |
|
288 // currentBuffer points to an allocated and filled HBufC8 |
|
289 // workingOffset tells us how far into the supplied descriptor the data we want is |
|
290 // aRemainder tells us how much data is left to copy. |
|
291 while( aRemainder ) |
|
292 { |
|
293 #ifdef __CACHELOG__ |
|
294 HttpCacheUtil::WriteFormatLog(0, _L(" %d bytes left to add to buffer"), aRemainder); |
|
295 #endif |
|
296 TInt possibleConsumptionInThisBlock = iBufferSize - currentBuffer->Length(); |
|
297 if( possibleConsumptionInThisBlock == 0 ) |
|
298 { |
|
299 #ifdef __CACHELOG__ |
|
300 HttpCacheUtil::WriteFormatLog(0, _L(" Buffer cannot be extended.")); |
|
301 #endif |
|
302 // block cannot extend, alloc a new one |
|
303 // the new one is either the correct length, or iBufferSize if aRemainder is too big. |
|
304 TInt spaceToAlloc = aRemainder < iBufferSize ? aRemainder : iBufferSize; |
|
305 currentBuffer = HBufC8::NewLC( spaceToAlloc ); |
|
306 iBufferList.AppendL( currentBuffer ); |
|
307 CleanupStack::Pop( currentBuffer ); |
|
308 possibleConsumptionInThisBlock = spaceToAlloc; |
|
309 #ifdef __CACHELOG__ |
|
310 HttpCacheUtil::WriteFormatLog(0, _L(" New buffer of %d bytes allocated"), spaceToAlloc); |
|
311 #endif |
|
312 // fill the block as far as possible |
|
313 currentBuffer->Des().Append( aDes.Mid( workingOffset, possibleConsumptionInThisBlock )); |
|
314 workingOffset += possibleConsumptionInThisBlock; |
|
315 aRemainder -= possibleConsumptionInThisBlock; |
|
316 } |
|
317 else |
|
318 { |
|
319 // block can extend |
|
320 if( possibleConsumptionInThisBlock >= aRemainder ) |
|
321 { |
|
322 #ifdef __CACHELOG__ |
|
323 HttpCacheUtil::WriteFormatLog(0, _L(" Current buffer can be extended to hold all data.")); |
|
324 #endif |
|
325 // we can realloc this buffer big enough to hold all the remaining data. |
|
326 currentBuffer = currentBuffer->ReAllocL( currentBuffer->Length() + aRemainder ); |
|
327 CleanupStack::PushL( currentBuffer ); |
|
328 iBufferList.Remove(iBufferList.Count()-1); |
|
329 iBufferList.AppendL( currentBuffer ); |
|
330 CleanupStack::Pop( currentBuffer ); |
|
331 // copy the data |
|
332 currentBuffer->Des().Append( aDes.Mid( workingOffset, aRemainder )); |
|
333 aRemainder = 0; |
|
334 } |
|
335 else |
|
336 { |
|
337 #ifdef __CACHELOG__ |
|
338 HttpCacheUtil::WriteFormatLog(0, _L(" Buffer cannot be extended to hold all data, consuming %d bytes."), possibleConsumptionInThisBlock); |
|
339 #endif |
|
340 // this buffer cannot extend to hold all the data. |
|
341 // take as much as we can - we will allocate a new buffer next time around. |
|
342 currentBuffer = currentBuffer->ReAllocL( currentBuffer->Length() + possibleConsumptionInThisBlock ); |
|
343 CleanupStack::PushL( currentBuffer ); |
|
344 iBufferList.Remove(iBufferList.Count()-1); |
|
345 iBufferList.AppendL( currentBuffer ); |
|
346 CleanupStack::Pop( currentBuffer ); |
|
347 // copy the data |
|
348 currentBuffer->Des().Append( aDes.Mid( workingOffset, possibleConsumptionInThisBlock )); |
|
349 // set up variables for next time around |
|
350 workingOffset += possibleConsumptionInThisBlock; |
|
351 aRemainder -= possibleConsumptionInThisBlock; |
|
352 } |
|
353 } |
|
354 } |
|
355 #endif |
|
356 #ifdef __CACHELOG__ |
|
357 HttpCacheUtil::WriteFormatLog(0, _L(" exiting AppendL. Segmented buffer now contains %d bytes"), this->Length()); |
|
358 #endif |
239 // will only exit here if we consumed all data |
359 // will only exit here if we consumed all data |
240 } |
360 } |
241 |
361 |
242 // ----------------------------------------------------------------------------- |
362 // ----------------------------------------------------------------------------- |
243 // CSegmentedHeapBuffer::Length |
363 // CSegmentedHeapBuffer::Length |