Notes |
|
(0012512)
|
zed
|
21-08-2013 07:14
|
|
Скорее всего из интернета приходят битые/недокачанные данные. Может закачка по таймауту отваливается, а САС этого не замечает, но 99,9% дело в качалке.
Как конкретно ругается jpeg? |
|
|
(0012513)
|
zed
|
21-08-2013 07:27
|
|
И можешь попробовать сохранить содержимое AData перед тем как оно бросает исключение чтобы посмотреть что оно там конкретно накачало и пытается открыть. |
|
|
|
> Скорее всего из интернета приходят битые/недокачанные данные.
Если бы все было так просто. Если бы сохранялся битый тайл он бы в кэше и оставался, а так при следующей перерисовке карты он отображается уже нормально и без ошибки.
>Как конкретно ругается jpeg?
Точно не помню, оно случается гораздо реже png, но общий смысл такой же, только ошибка от libjpeg |
|
|
|
> И можешь попробовать сохранить содержимое AData перед тем как оно бросает исключение чтобы посмотреть что оно там конкретно накачало и пытается открыть.
Увы не могу. На этом компе делфы нет и ставить нельзя под угрозой репрессий. |
|
|
(0012516)
|
zed
|
21-08-2013 07:31
|
|
Но в режиме "Только из кэша" такого не наблюдается? |
|
|
|
>Но в режиме "Только из кэша" такого не наблюдается?
Нет, не наблюдается, но это не значит, что виновата именно качалка. Может это из-за ошибки при сохранении тайла. |
|
|
(0012519)
|
zed
|
21-08-2013 07:34
|
|
>На этом компе делфы нет и ставить нельзя под угрозой репрессий.
Ну ты попал :) Скомпилить exe с сохранением AData при ошибке? |
|
|
|
Скомпиль, если не сильно сложно. |
|
|
|
>Ну ты попал :)
Ага. Причем это касается любого нелицензионного софта. Даже за Daemon Tools, поставившим его погрозили пальчиком и сказали так больше не делать :) |
|
|
(0012526)
|
zed
|
21-08-2013 08:02
|
|
Будет сохранять проблемные тайлы в %TEMP% c префиксом "SAS" (в файлы вида SASXXXX.tmp) |
|
|
|
Как ни странно это действительно битые png. |
|
|
|
Воспроизвел ошибку на файловом тайлохранилище, а потом нашел файл похожий на тот что сохранился в темпе. В темпе записалось начало правильного тайла, но только половина. Похоже проблема в том, что в одном потоке мы сохраняем файл, причем ОС уже отрапортовала о завершении операции и мы разлочили синхронизатор, а в другом потоке при чтени мы получаем только начало файла, которое успело записаться. Смущает только то, что воспроизводится на БерклиДБ |
|
|
(0012529)
|
zed
|
21-08-2013 12:43
|
|
>причем ОС уже отрапортовала о завершении операции и мы разлочили синхронизатор
Т.е. хочешь сказать, что оно в буфере винды и на диск ещё толком не записалось? Но для читающего потока винда же должна была отдать из буфера без проблем. А в Беркли к тому же, есть ещё и мем-кэш внутри САС, т.е. оно к диску/БД даже и не должно было обращаться (на чтение). |
|
|
|
Я завел этот инцидет, именно потому что не понимаю что происходит. Факт в том, что записало оно полный файл, а прочитало для отображения меньше половины этого файла. Что удивительно это происходит как с файлами так и берклиДБ. Где оно может портится? |
|
|
(0012531)
|
zed
|
21-08-2013 12:57
|
|
Может сбоит ITileObjCacheBitmap? |
|
|
|
Нее, проблема еще до декодирования. А ITileObjCacheBitmap хранит уже раскодированные битмапки. |
|
|
(0012533)
|
zed
|
21-08-2013 13:48
|
|
Перед сохранением в кэш ещё может сработать обрезка/ресайз, которая декодирует тайл. Т.е. у тебя может быть ситуация, что оно обломилось один раз с кропом и тайл таки НЕ сохранился в кэш, а потом пришёл следующий поток и успешно докачал и сохранил тайл. Вот и получилось, что и в кэше есть и ошибку ты увидел. |
|
|
|
Это могло бы быть так, но даже на скриншоте ошибка в Гибрид (Wikimapia) взятом из репозитория. А там никакой обрезки и ресайза при сохранении нет. Даже перекодирования из формата в другой формат быть не может, потому что ожидается только png (или текст, который считается эквивалентным png) |
|
|
|
>прочитало для отображения меньше половины этого файла
>а потом пришёл следующий поток и успешно докачал и сохранил тайл
Если запустить Filemon - это всё видно будет размеры буферов и порядок вызовов. |
|
|
|
Запустил ProcessMonitor. Все стало очень интересно.
Сначала прилетает
SetEndOfFileInformationFile EndOfFile: 5 440
Потом пара чтений
Потом опять
SetEndOfFileInformationFile EndOfFile: 8 416
Похоже дело таки в качалке тайлов.
Судя по всему дело в том, что в процессе закачки запросы на закачку тайла ставятся в очередь и отменяются. Но отмененный запрос, частично закачанный, почему-то сохраняется в базу, но потом сразу перетирается неотмененным запросом, но на быстром компе отображалка успевает подхватить тот битый тайл. |
|
|
|
А sacs тоже affected?
Я там переделывал сохранение тайла на диск для файловых хранилищ, чтобы в рамках одного открытия файла по хэндлу всё делать, а не через установку размера Stream. |
|
|
(0012540)
|
zed
|
22-08-2013 08:27
|
|
А Беркли это значит каснулось из-за мем-кэша. В тайловый кэш по-моему так никто мем-кэш и не прикрутил? |
|
|
(0012541)
|
zed
|
22-08-2013 08:29
|
|
>а не через установку размера Stream
А какая разница, если прилетает 2 отдельных запроса на запись? |
|
|
|
>А sacs тоже affected?
Не проверял, но подозреваю, что да.
> Я там переделывал сохранение тайла на диск для файловых хранилищ, чтобы в рамках одного открытия файла по хэндлу всё делать, а не через установку размера Stream.
Там ошибка на уровень выше. То есть, записали битый тайл, а потом переписали полным. Так что воспроизведется на всех типах тайлохранилищ. |
|
|
|
> А Беркли это значит каснулось из-за мем-кэша. В тайловый кэш по-моему так никто мем-кэш и не прикрутил?
Без разницы, что с мем-кэшом, что без. Проходят две операции записи в тайлохранилище. А между ними успевает пройти чтение. |
|
|
(0012544)
|
vasketsov
|
22-08-2013 08:35
(edited on: 22-08-2013 08:36) |
|
>Проходят две операции записи в тайлохранилище
>если прилетает 2 отдельных запроса на запись?
Это ты как понял? По ProcessMonitor-у? )))
|
|
|
|
>Это ты как понял? По ProcessMonitor-у? )))
Ага. Плюс знание, что сейчас там есть блокировка на каждом тайлохранилище. Все операции сериализовались вполне нормально. Так что проблема в качалке. |
|
|
|
Но ты всё же проверь sacs.
>проблема в качалке
И в чём же она заключается-то в качалке?
>сразу перетирается неотмененным запросом
В том, что на один тайл непрокачанного экрана может быть 2 запроса на скачку? Так я об этом сто лет назад ещё писал.
>Но отмененный запрос
Почему запрос отменяется? |
|
|
|
>Но ты всё же проверь sacs.
Проверю
>>проблема в качалке
>И в чём же она заключается-то в качалке?
В том, что качалка сохраняет полученные данные, даже если запрос на закачку отменен в процессе обработки, или в том, что оно прерывает запрос, который начал обрабатываться, после сдвига карты.
>Почему запрос отменяется?
Потому что карту подвинули и нас в первую очередь интересуют уже другие тайлы, чем интересовали раньше. |
|
|
|
>Но ты всё же проверь sacs.
Проверил. Все ровно то же самое, что и не удивительно. |
|
|
(0012553)
|
vasketsov
|
22-08-2013 10:45
(edited on: 22-08-2013 10:47) |
|
>сохраняет полученные данные, даже если запрос на закачку отменен
Результат (HTTP code) запроса какой будет (должен быть), если он отменён? 200 OK?
А какую-нибудь мегастарую версию пробовал запускать?
|
|
|
|
>Результат (HTTP code) запроса какой будет (должен быть), если он отменён? 200 OK?
ХЗ. Я это в свое время делал для прямого использования WinInet. Потом Zed переделал на TALWinInetHTTPClient. Как оно сейчас работает, для меня почти загадка :) |
|
|
(0012555)
|
zed
|
22-08-2013 10:56
|
|
При отмене запроса вызывается disconnect, и если у нас не возникает никакого исключения (не уверен, что alcinoe бросает в этом случае что-то) идёт вызов OnAfterResponse, в котором как раз и нету никакой проверки на то, что запрос отменён. |
|
|
(0012556)
|
zed
|
22-08-2013 10:59
|
|
А Http code там будет 200, потому как вначале прилитают заголовки со статусом, а только потом тело. И если тело пришло не до конца, заголовки-то уже никто не будет исправлять. Конечно, если был разрыв связи на сокете, то мы словим исключение и уже не будем анализировать то что там успело накачаться. |
|
|
|
Ну вот похоже туда и нужно добавить проверку. |
|
|
|
Zed можешь перед строчками
if Result = nil then begin
Result := OnAfterResponse(
ARequest,
FResultFactory
);
end;
добавить проверку
if ACancelNotifier.IsOperationCanceled(AOperationID) then begin
Result := FResultFactory.BuildCanceled(ARequest);
end;
и выложить где-то скомпиленную с этой проверкой версию?
|
|
|
(0012559)
|
zed
|
22-08-2013 11:18
|
|
Сделал так:
if
(Result = nil) and
(not ACancelNotifier.IsOperationCanceled(AOperationID)) and
(FDisconnectByServer = 0) and
(FDisconnectByUser = 0)
then begin
Result := OnAfterResponse(
ARequest,
FResultFactory
);
end else begin
Result := FResultFactory.BuildCanceled(ARequest);
end;
Тестируй. |
|
|
(0012560)
|
zed
|
22-08-2013 11:20
|
|
Меня там по коду в юните смущает доступ к переменным FDisconnectByServer и FDisconnectByUser без синхронизации. Это vasketsov добавлял, если что :) |
|
|
|
>Меня там по коду в юните смущает доступ к переменным FDisconnectByServer и FDisconnectByUser без синхронизации. Это vasketsov добавлял, если что :)
Понятия не имею. Я вообще не понял нафиг оно там нужно. В крайнем случае можно заменить флаг построенный на Interlocked* |
|
|
|
Что-то оно у меня вообще качать перестало |
|
|
|
>без синхронизации
ЕМНИП это Byte - а операции с Byte атомарны и без синхронизации
>не понял нафиг оно там нужно
ну очевидно это флаги отбоя по инициативе сервера или по инициативе пользователя
>vasketsov добавлял
значит известен тикет или хотя бы комментарии какие, почему такое сделано |
|
|
(0012564)
|
zed
|
22-08-2013 11:49
|
|
> значит известен тикет
Changeset: 5096 (9bbf5ab98d53) 1103: обработка дисконнекта для TALWinInetHTTPClient
User: vasketsov
Date: 2012-02-25 19:59:58 +0400 (18 months)
Конечно, все ходы записаны :) |
|
|
(0012565)
|
zed
|
22-08-2013 11:50
|
|
>Что-то оно у меня вообще качать перестало
У меня качает исправно. |
|
|
|
А у меня ни одного скачанного тайла |
|
|
|
>все ходы записаны
У меня даже больше инфы есть:
http://sasgis.org/mantis/view.php?id=1103#c5629
это про причину, читать от ссылки и далее. |
|
|
|
Я понял почему ошибки именно на слое гибрида викимапии у меня сыпятся - там сервер не отдает Content-Length в заголовке ответа. А у гугла отдает. |
|
|
|
Почитал код, вспомнил что там происходит. Я ошибся. Отмены начатого запроса на закачку тайла не происходит. Точнее происходит, но только если удаляется качальщик по таймауту или при закрытии программы. Так что судя по всему отлуп получаем на уровне сервера, а так как гибрид викимапии не возвращает Content-Length то и получаем недокачанные тайлы. Или я даже не знаю в чем проблема.
Вариантов два:
1. понять кто виноват, и что делать
2. не отправлять одновременно одинаковые запросы.
Второй вариант логичнее, но возникает вопрос как его реализовывать.
Кратко опишу как сейчас работает закачка тайлов:
1. Есть поток отвечающий за закачку видимой области конкретной карты. После каждого существенного сдвига карты пользователем старые запросы помечаются как отмененные, а в очередь запихивается новая пачка запросов.
2. Есть очередь запросов на закачку тайлов, в которую помещаются объекты-запросы содержащие зум, координаты тайла, версию. Очередь тупая FIFO, но у каждого запроса есть признак отменен ли он.
3. Есть определенное количество обработчиков очереди. Каждый обработчик забирает очередной запрос из очереди и начинает обрабатывать.
4. Если запрос уже отменен, то просто ничего не делаем, идем получать следующий запрос.
5. При помощи паскаль скрипта строим запрос на закачку включая хедеры + возможно в процессе выполняем какие-то HTTP запросы при помощи принадлежащего обработчику HTTP-загрузчику.
6. Если запрос отменен, то увы, выбрасываем построенный запрос и идем за следующей задачей.
7. Выполняем HTTP запрос при помощи все того же принадлежащего обработчику HTTP-загрузчику
8. Если мы выполнили HTTP запрос, то даже если запрос на тайл отменен, все равно сообщаем что скачали тайл и сохраняем его, если ошибки не было.
Итого вопрос. Куда и как пихать проверку дублирующихся HTTP запросов или как переделать всю эту кухню, что бы оно работало максимально эффективно. |
|
|
|
Возможно стоит добавить проверку наличия тайла непосредственно перед HTTP-запросом, если стоит режим Кэш+Интернет, или закачка идет в режиме без замены тайлов.
Но это никак не поможет от одновременных запросов одного и того же тайла, если один из обработчиков очереди уже начал HTTP запрос, который потом отменили и заменили новым, и другой обработчик начал его выполнять. |
|
|
|
>возникает вопрос как его реализовывать
Ну вариантов минимум два:
1. Дополнительный признак невозможности пользовательской отмены запроса. Соответственно подымать этот признак и не отменять запрос, если он уже прошёл какую-то стадию (в смысле http). Но при вырубании приложения вырубаются все. Возможно для чего-то другого тоже потребуется такое поведение (например, для операции, которую прерываем после тяжёлых промежуточных этапов, когда остался один простой лёгкий). Универсально и широкоиспользуемо в технике.
2. Внутренний список xyzv в том месте, одном на одну карту, в котором эти параметры ещё есть (возможно в httpdownloader они уже отсутствуют), там держать актуальный список, добавлять в начале закачки, выкидывать в конце закачки. По месту и тормоза.
Это если без сильных извратов.
>стоит добавить проверку наличия тайла непосредственно перед HTTP-запросом
Этого делать точно не стоит ввиду полной бессмысленности: если есть такой же параллельный поток на скачку, тайл ещё просто не упадёт.
Кроме того, какой тайл проверять, если скачанный мегатайл нарезается на кучку стандартных? |
|
|
|
1-й вариант совсем ничего не помогает, ибо оно и так не отменяется, а причин не добавлять новый запрос все так же нет. Точнее оно сейчас именно так и есть, и ты бы этого не писал, если бы внимательно прочитал то, что написал я.
2-й ваниант вызывает вопрос. И что делать если тайл уже есть в списке?
>>стоит добавить проверку наличия тайла непосредственно перед HTTP-запросом
>Этого делать точно не стоит ввиду полной бессмысленности: если есть такой же параллельный поток на скачку, тайл ещё просто не упадёт.
А если он уже упал, пока этот запрос в очереди стоял? Шансы очень даже большие. |
|
|
|
>ибо оно и так не отменяется
Отменяется - имел в виду подымается отметка об отмене, а не фактическую отмену.
>причин не добавлять новый запрос все так же нет
Наличие запроса в очереди - не причина?
>оно сейчас именно так и есть
Неправда. Сейчас отмена операции 146% взводит признак отмены операции, даже если операция фактически выполнилась. Попробуй подумать снова.
>2-й вариант вызывает вопрос. И что делать если тайл уже есть в списке?
Очевидно ничего, ибо можно дождаться первичного запроса, и не рожать вторичный. |
|
|
|
>Наличие запроса в очереди - не причина?
Я же написал, что очередь тупая, там нет метода проверки есть ли какой-то запрос в очереди или нет. Плюс сейчас отменяется все запросы скопом, если захочется делать поштучную отмену, то придется много чего переделывать.
>>оно сейчас именно так и есть
>Неправда. Сейчас отмена операции 146% взводит признак отмены операции, даже если операция фактически выполнилась. Попробуй подумать снова.
Сам подумай. Если начался http запрос то этот признак дальше уже игнорируется и больше не учитывается.
>>2-й вариант вызывает вопрос. И что делать если тайл уже есть в списке?
>Очевидно ничего, ибо можно дождаться первичного запроса, и не рожать вторичный.
В смысле не рожать вторичный? Проигнорировать вторичный. А рожать нужно. Или вводить методы изменения приоритета для запросов, что бы тайлы в нынешнем центре экрана загружались в первую очередь. |
|
|
|
>Если начался http запрос то этот признак дальше уже игнорируется и больше не учитывается
А как же проверка после окончания запроса, которая обсуждалась выше?
А кроме того, логично, что если запрос нельзя отменить, то ему нельзя и Disconnect руками сделать. Такое ощущение, что всё разжевать надо...
>очередь тупая, там нет метода проверки есть ли какой-то запрос в очереди или нет
У тебя же сейчас есть хэши - натяни проверку по хэшу xyzv.
>вводить методы изменения приоритета для запросов
Ты какую-то ересь несёшь. Ну при чём тут приоритеты, если не прокачаться может ЛЮБОЙ участок экрана? |
|
|
|
Так. Давай для начала ты внимательно посмотришь код, а потом будешь писать предположения как оно работает.
> А как же проверка после окончания запроса, которая обсуждалась выше?
Я сегодня с этого начал, что эта проверка срабатывает только при закрытии программы. Во всех остальных случаях, если запрос на закачку тайла добрался до Http он будет выполнен и его отмена игнорируется.
>>очередь тупая, там нет метода проверки есть ли какой-то запрос в очереди или нет
>У тебя же сейчас есть хэши - натяни проверку по хэшу xyzv
Для этого придется полностью переделывать очередь. Там сейчас только два метода Push и Pop.
>Ну при чём тут приоритеты, если не прокачаться может ЛЮБОЙ участок экрана?
Ничего не понял. |
|
|
|
>Ничего не понял
Это неудивительно. Попробуй завтра попробовать. Сегодня видимо не твой день.
Потому что в здравом уме такое написать нереально:
вводить методы изменения приоритета для запросов, что бы тайлы в нынешнем центре экрана загружались в первую очередь
>придется полностью переделывать очередь. Там сейчас только два метода Push и Pop
Почему Push внутри не может это сам проверять?
>Давай для начала ты внимательно посмотришь код
Давай.
>срабатывает только при закрытии программы
То есть TDownloaderHttp.OnCancelEvent (и Disconnect оттуда) при сдвиге карты не сработает? Зачем тогда FCancelListener цепляется к ACancelNotifier? |
|
|
|
>>Ничего не понял
>Это неудивительно. Попробуй завтра попробовать. Сегодня видимо не твой день.
Попробуй завтра написать другими словами. Сегодня ты несешь бред видимо не твой день. (Ты первый начал)
>>срабатывает только при закрытии программы
>То есть TDownloaderHttp.OnCancelEvent (и Disconnect оттуда) при сдвиге карты не сработает? Зачем тогда FCancelListener цепляется к ACancelNotifier?
Я третий раз пишу, что ACancelNotifier это совсем другой CancelNotifier чем тот что передается при создании запроса тайла, и он срабатывает только при удалении объекта обработчика очереди и при завершении работы программы. |
|
|
|
>первый начал
Неправда. Сообщения 12641 и 12642 уже содержат признаки тяжёлого повреждения ЦНС. Я лишь отвечаю на твой бред.
Например, для начала поясни, каким образом неотправка одинаковых запросов тебя спасёт? А если это будут одинаковые запросы от двух разных включённых слоёв, работающих по одному тайлохранилищу и по одному картосервису? Или отныне сас будет только строем ходить и в ногу?
Я не зря призываю тебя подумать ещё раз.
То что ты надумал сейчас - ересь 146%.
Поверь, что со стороны виднее.
Про приоритеты центра экрана - чистейший диагноз.
Такое ощущение, что или ты пьян, или аккаунт взломан, но это не vdemidov.
>Я третий раз пишу
Лучше ответь просто, "да" или "нет", вызывается Disconnect при сдвиге карты или нет? |
|
|
(0013753)
|
zed
|
06-02-2014 21:35
|
|
В связи с доработкой 0002307 нужно подтверждение воспроизводимости бага в новом свете. |
|
|
|
Да, починилось. Я все еще считаю что качалку видимой области нужно переделать и избавиться от отдельного треда на каждую карту, но и так гораздо лучше чем было. Спасибо. |
|