Ошибка чтения потока - PullRequest
       2

Ошибка чтения потока

3 голосов
/ 16 марта 2011

Я получаю это сообщение об ошибке при большой нагрузке. Вот абстрактный код и сообщение из моего журнала ошибок. Я перепробовал все, что мог придумать. Любое предложение будет с благодарностью.

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;

Записи в журнале:

 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;

И вызывающая функция:

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;

`

Ответы [ 2 ]

8 голосов
/ 16 марта 2011

Вы не используете правильную блокировку. Вы получаете блокировку read для массива записей кэша, но как только вы найдете нужный элемент, вы модифицируете его. Сначала вы явно изменяете его, назначая его свойство Position, а затем неявно изменяете его, читая его, что снова изменяет его свойство Position. Когда другой код попытается прочитать из того же элемента кэша, у вас будут помехи. Если свойство Position исходного потока изменяется между временем, когда целевой поток вычисляет, сколько байтов доступно, и временем, которое он фактически запрашивает для чтения этих байтов, вы получите ошибку чтения потока.

У меня есть пара советов, связанных с этим:

  • Во-первых, не используйте потоки в качестве устройства хранения. Вы очевидно держите содержимое файлов. Вы не собираетесь их менять, поэтому вам не нужна структура данных, предназначенная для последовательных изменений. Вместо этого просто храните данные в простых байтовых массивах: TBytes. (Кроме того, использование TStringStream, в частности, вводит в заблуждение относительно важности кодировок этих строк. Простой файловый кеш вообще не должен касаться кодировок строк. Если вы должны использовать поток, используйте класс, независимый от контента, такой как TMemoryStream.)
  • Не подавлять исключение, которое вы на самом деле не обработали. В этом коде вы перехватываете все типы исключений, регистрируете некоторую информацию, очищаете кеш, а затем продолжаете, как будто все нормально . Но вы ничего не сделали для решения проблемы, которая вызвала исключение, поэтому все не нормально. Поскольку вы на самом деле не обрабатываете исключение, вам необходимо убедиться, что оно распространяется на вызывающую сторону. Позвоните raise после того, как позвоните Clear. (И когда вы регистрируете исключение, убедитесь, что вы записали значение ClassName исключения, а также его сообщение.)
1 голос
/ 16 марта 2011

Похоже, что-то внешнее блокирует ваши потоковые файлы.

Вы можете попробовать Process Monitor , чтобы увидеть, что его блокирует.

Еще одна вещь, которую вы можете попробовать, - открыть поток в режиме чтения-запрета-записи (пожалуйста, покажите нам, как вы открываете поток).

Примерно так:

Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite) ;

Редактировать 1: Не обращать внимания на удар через деталь: вы используете TStringStream.
Я оставлю ответ на всякий случай, если кто-либо когда-либо получит такую ​​ошибку при использовании TFileStream.

Редактировать 2: Юрий опубликовал это интересное дополнение, но я не уверен, что оно будет работать, так как BlobStream не инициализирован, как Роберт Лав подозревается:

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; 

- Йерун

...