Stream read error
Solution 1
You're not using correct locking. You're acquiring a read lock on the array of cache entries, but once you find the item you want, you modify it. First, you explicitly modify it by assigning its Position
property, and then you implicitly modify it by reading from it, which modifies its Position
property again. When other code attempts to read from that same cache item, you'll have interference. If the source stream's Position
property changes between the time the destination stream calculates how many bytes are available and the time it actually requests to read those bytes, you'll get a stream-read error.
I have a couple pieces of advice related to this:
- Don't use streams as a storage device in the first place. You're apparently holding the contents of files. You're not going to change those, so you don't need a data structure designed for making sequential changes. Instead, just store the data in simple arrays of bytes:
TBytes
. (Also, use ofTStringStream
in particular introduces confusion over whether those strings' encodings are important. A simple file cache shouldn't be concerned with string encodings at all. If you must use a stream, use a content-agnostic class likeTMemoryStream
.) - Don't quell an exception that you haven't actually handled. In this code, you're catching all exception types, logging some information, clearing the cache, and then proceeding as though everything is normal. But you haven't done anything to resolve the problem that triggered the exception, so everything is not normal. Since you're not really handling the exception, you need to make sure it propagates to the caller. Call
raise
after to callClear
. (And when you log the exception, make sure you log the exception'sClassName
value as well as its message.)
Solution 2
It looks like something external is blocking your stream files.
You could try to use Process Monitor to see what blocks it.
Another thing you can try is to open the stream in read-deny-write mode (please show us how you open the stream).
Something like this:
Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite) ;
Edit 1: Disregard the strike through part: you are using TStringStream.
I'll keep the answer just in case anyone ever gets this kind of error when using TFileStream.
Edit 2: Yuriy posted this interesting addendum, but I'm not sure it will work, as the BlobStream
is not initialized, just like Robert Love suspected:
Function TCacheInMemory.CacheCheck(cName: String; Out BlobStream: TStringStream): Boolean;
Begin
Result := False;
Try
If Not IfUseCache Then
exit;
BlobStream.SetSize(0);
BlobStream.Size := 0;
StreamValue(trim(cName), True, BlobStream);
If BlobStream.Size > 0 Then
Result := True;
Except
On E: Exception Do
Begin
x.xLogError('LogErrorCacheInMemory.txt', 'CheckCacheOutStream:' + E.Message + ' ItemsCount:' + IntToStr( High(fItems)) + 'Memory:' + IntToStr(x.GetMemoryInfoMemory));
End;
End;
End;
--jeroen
Yuriy
Updated on June 05, 2022Comments
-
Yuriy almost 2 years
I'm getting this error message under heavy load. Here is code abstract and message from my error log. I tried everything I could think of. Any suggestion would be greatly appreciated.
Procedure tCacheInMemory.StreamValue(Name: String; IgnoreCase: Boolean; Var Stream: TStringStream); Var i: Integer; Begin i := 0; Try If Not active Then exit; arrayLock.BeginRead; Try i := Search(Name); If i > -1 Then Begin If fItems[i].value = Nil Then exit; fItems[i].value.Position := 0; Stream.Position := 0; Stream.CopyFrom(fItems[i].value, fItems[i].value.Size); End; Finally arrayLock.EndRead; End; Except { ...execution jumps to here } On E: Exception Do Begin x.xLogError('LogErrorCacheInMemory.txt', 'StreamValue:' + E.Message + ' ItemsCount:' + IntToStr( High(fItems)) + 'Memory:' + IntToStr(x.GetMemoryInfoMemory) + endLn + 'StreamSize : ' + IntToStr(fItems[i].value.Size) + ' i=' + IntToStr(i) + 'Name: ' + Name); Clear; End End; End;
Log Entries:
3/10/2011 10:52:59 AM: StreamValue:Stream read error ItemsCount:7562 Memory:240816 StreamSize : 43 i=7506 Name: \\xxxxxxxx\WebRoot\\images\1x1.gif 3/10/2011 12:39:14 PM: StreamValue:Stream read error ItemsCount:10172 Memory:345808 StreamSize : 849 i=10108 Name: \\xxxxxxxx\WebRoot\\css\screen.add.css 3/10/2011 3:45:29 PM: StreamValue:Stream read error ItemsCount:11200 Memory:425464 StreamSize : 3743 i=11198 Name: \\xxxxxxxx\WebRoot\\JS\ArtWeb.js
P.S.
arrayLock: TMultiReadExclusiveWriteSynchronizer; fItems: Array Of rCache; Type rCache = Record Name: String; value: TStringStream; expired: TDateTime; End;
And calling function:
Function tCacheInMemory.CacheCheck(cName: String; Out BlobStream: TStringStream): Boolean; Begin Result := False; If Not IfUseCache Then exit; BlobStream.SetSize(0); BlobStream.Size := 0; StreamValue(trim(cName), True, BlobStream); If BlobStream.Size > 0 Then Result := True; End;
`