Как обеспечить целостность данных в EEPROM памяти и FLASH памяти с постраничным стиранием?
Добрый день!
Возникла проблема с обеспечением целостности данных при хранении данных в памяти с постраничным стиранием.
Память AT45DB321.
В частности есть устройство, которое имеет много сохраненных в памяти структур данных. Эти структуры никак не связаны друг с другом, они могут в произвольном порядке изменяться с сервера, добавляться новые, деактивироваться старые.
И вот тут я задумался о том как быть с потенциально возможной ситуацией:
- прилетело уведомление что нужно заменить структуру STRUCT_N, которая находиться посереди страницы памяти MEM_PAGE_X,
- я запускаю процесс перезаписи страницы (либо путем вычитки страницы в ОЗУ и заменой нужных мне данных, либо внутренними средствами микросхемы),
- в процессе перезаписи произошел сбой питания, оно пропало (либо после стирания, либо когда данные начали грузиться в память),
- после восстановления питания у меня получается ситуация что кроме текущей редактируемой структуры у меня пострадали еще структуры, находящиеся на той же странице что и редактируемая структура. Да, я не получил от девайса ответа что редактируемая структура была изменена и я повторю данную операцию. Но как быть с остальными данными?
Проблема осложняется тем, что сервер абсолютно не владеет информацией о фрагментации памяти, на каких страницах какие структуры хранятся и т.е. я понятия не имею какие именно структуры я потерял совместно с редактируемой структурой.
Посоветуйте, пожалуйста, какие меры можно предпринять чтобы избежать подобного?
Один из вариантов, который я вижу (не самое интересное как по мне решение):
- формировать на сервере прямо блоки данных (с контрольными суммами),
- при каких-либо изменениях сначала редактируются данные на сервере, пересчитывается контрольная сумма,
- после этого отправляется команда модификации на девайс и в ответе должна прийти контрольная сумма блока памяти девайса,
- если совпало - то все ОК, если не совпало - грузим полный блок кода с сервера на девайс.
Однако при это получается слишком сильная связь сервер-девайс, т.е. если я перешел на другую структуру памяти или другую микросхему с другим размером страницы-блока, то мне нужно и на сервере вносить изменения в алгоритм работы.
Хотя с другой стороны это упростит задачу периодического контроля целостности данных, т.е. раз в N-й промежуток времени сервер просит дать ему контрольные суммы памяти и сверяет со своими данными.
Стоит ли заморачиваться с этим?
А нужна ли вам вообще EEPROM при наличии коннекта к серверу?
У вас есть два варианта - решить проблему аппаратно, навесив конденсатор и сделав контроль внешнего питания.
Или написав хитрую систему хранения по типу журналируемой фс, которая будет при старте проверять структуру блоков и, используя сквозную контрольную сумму, выявлять блок, который был недозаписан. Понятно, что развозить это все на протокол коммуникации с сервером - никуда не годная идея, устройство должно следить за своей памятью само.
Странно, вроде бы писал ответ Вам, но он исчез из сообщений. На всякий случай продублирую. Фокс Йовович, соединение с сервером не постоянно, в случае если девайс переходит в оффлайн, то он должен продолжить полноценно функционировать.
В девайсе будет присутствовать схема бесперебойного питания на случай пропадания основного питания, но, насколько я понял из разной информации (на своем опыте пока не сталкивался), информация может "биться" и при нормальном питании. Хотелось бы избежать подобной ситуации.
Я думал по поводу журналирования как делается в СУБД, однако боюсь что здесь может получиться ситуация что проблемы скорее начнутся из-за потенциальных багов в самой программы (ввиду возросшей сложности алгоритма).
Потому пытаюсь искать нечто оптимальное с точки зрения надежность/сложность.
Насчет сквозной контрольной суммы, проверки при старте это интересно, попробую подумать какую избыточность мне добавить в данные чтобы при старте была возможность восстановить данные.
Обверните структуры в "пакеты". Длинна структуры у вас не меняется, изменяется только содержимое. Тогда делаете примерно такой пакет:
[МАРКЕР_НАЧАЛА_СТРУКТУРЫ][ДЛИННА_СТРУКТУРЫ][ДАННЫЕ_СТРУКТУРЫ][CRC-8_СТРУКТУРЫ][МАРКЕР_КОНЦА_СТРУКТУРЫ]
Изменяться у вас будет только [ДАННЫЕ_СТРУКТУРЫ] и [CRC-8_СТРУКТУРЫ].
Как результат сможете легко пробежать по всей памяти, найти все структуры, сравнить crc, обнаружить битые и решать что с этим делать т.к. сможете только предсказать что вот тут явно что то не так.
Как минус избыточный объем данных за счет маркеров, длинны и crc. Но это можно оптимизировать исходя из ваших реалий, скажем если структуры не особо длинные то [МАРКЕР_НАЧАЛА_СТРУКТУРЫ][ДЛИННА_СТРУКТУРЫ] можно объединить в 1 байт вместо 2х(2-3 или 4 бита отдать под маркер а остальное под длинну).
Дмитрий Александров, добавление crc8 особо данные не увеличит, так что думаю это будет нормально.
Хорошая идея насчет того чтобы добавить контрольные суммы к каждой структуре (изначально я думал постранично добавлять).
Также подумаю насчет того как реализовать copy-on-write алгоритм чтобы оставлять в памяти хотя бы одну копию предыдущих данных.
Ваша проблема в одном : "- в процессе перезаписи произошел сбой питания, оно пропало".
Это вопрос чисто аппаратный на уровне правильности выбранной структуры проектируемого изделия.
Если разработчик железа не предусмотрел возможности "сообщить" ПО о проблемах с питанием и/или не
принял мер защиты от пропадания питания на стадии проектирования, то ваши попытки исправить это
программно вряд ли будут успешны.
acex101, это я утрировал ситуацию. На самом деле я больше стараюсь обойти ситуацию когда что-то пошло не так и не всегда проблема лежит на поверхности как то пропадание питания. Могут быть опять таки проблемы с битыми данными после сотен тысяч перезаписей ячеек. И это желательно не просто постараться обойти размазыванием этого кол-ва по максимально возможному кол-ву ячеек чтобы уменьшить нагрузку на каждую из них, но и выявить эту проблему максимально быстро и дать возможность принять какие-то меры (либо пометить ячейку наподобии bad секторов винчестера, либо еще что-то).
Потому мне и хотелось понять как сделать "правильно".
Одна из проблем на фирмах, занимающихся разработкой это когда программисты тыкают пальцами на электронщиков что это аппаратная проблема если что-то пошло не так (а не всегда в реальности можно понять что именно пошло не так если это не массовые отказы), а электронщики в свою очередь пинают на кривой код программистов.
Я считаю что нужно как программно так и аппаратно по максимуму постараться обеспечить надежность устройства.