Сохранение в поток (постановка)
SYSDBA (обсуждение | вклад) (→Переработанный алгоритм сохранения в поток) |
SYSDBA (обсуждение | вклад) (→Тестирование) |
||
| (не показаны 15 промежуточных версий 1 участника) | |||
| Строка 2: | Строка 2: | ||
# Увеличение скорости минимум в 10 раз; | # Увеличение скорости минимум в 10 раз; | ||
# Уменьшение размера файла минимум в 10 раз (при использовании двоичного формата); | # Уменьшение размера файла минимум в 10 раз (при использовании двоичного формата); | ||
| − | # Возможность сохранения в формате XML; | + | # Возможность сохранения в дфоичном формате, в тексте и в XML; |
# Предусмотреть возможность сохранения только объектов измененных после указанной даты; | # Предусмотреть возможность сохранения только объектов измененных после указанной даты; | ||
# Предусмотреть возможность инкрементного сохранения объектов; | # Предусмотреть возможность инкрементного сохранения объектов; | ||
| Строка 10: | Строка 10: | ||
# Процедура должна обрабатывать миллион записей на компьютере с 512 Мб оперативной памяти за приемлемое время; | # Процедура должна обрабатывать миллион записей на компьютере с 512 Мб оперативной памяти за приемлемое время; | ||
# Формирование потока данных и загрузка его на базу должна осуществляться не в монопольном режиме. | # Формирование потока данных и загрузка его на базу должна осуществляться не в монопольном режиме. | ||
| + | # Предусмотреть возможность блокировки на изменение записей, переданных на другую базу. | ||
| + | # Реализовать корректный механизм замены и объединения данных объектов. | ||
См. сравнение механизмов репликации и сохранения данных в поток в статье [[Сохранение в поток и репликация]]. | См. сравнение механизмов репликации и сохранения данных в поток в статье [[Сохранение в поток и репликация]]. | ||
| Строка 29: | Строка 31: | ||
|- valign="top" | |- valign="top" | ||
|Пользователь производит загрузку потока на базу данных. | |Пользователь производит загрузку потока на базу данных. | ||
| − | |Ускорения процесса. Контроля над ходом выполнения и возможности прервать процесс в любой момент времени. Внятного разрешения конфликтных ситуаций: Обновлять записи всегда, Обновлять записи только если они новее, чем те, что находятся в базе данных, Пропускать записи. Возможности выставить действие по-умолчанию как для всего процесса, так и для объектов конкретного типа. | + | |Ускорения процесса. Контроля над ходом выполнения и возможности прервать процесс в любой момент времени. Внятного разрешения конфликтных ситуаций: Обновлять записи всегда, Обновлять записи только если они новее, чем те, что находятся в базе данных, Пропускать записи. Возможности выставить действие по-умолчанию как для всего процесса, так и для объектов конкретного типа. Возможности сравнивать данные объектов при возникновении конфликта перезаписи уже существующего объекта. Возможности слияния данных двух объектов (подобно той, которая существует в механизме объединения двух записей). |
|- valign="top" | |- valign="top" | ||
|Пользователь имеет головную базу и несколько перефирийных, на которых происходит редактирование данных. Периодически данные с перефирийных баз передаются на головную для консолидации, причем изменения от головной базы данных не передаются на перефирийные и изменения от одной перефирийной базы данных не передаются на другую. | |Пользователь имеет головную базу и несколько перефирийных, на которых происходит редактирование данных. Периодически данные с перефирийных баз передаются на головную для консолидации, причем изменения от головной базы данных не передаются на перефирийные и изменения от одной перефирийной базы данных не передаются на другую. | ||
| − | |Возможности инкрементной передачи данных. Т.е. перадаваться должны только объекты измененные (добавленные) с момента последней передачи. | + | |Возможности инкрементной передачи данных. Т.е. перадаваться должны только объекты измененные (добавленные) с момента последней передачи. Возможности передавать информацию об удаленных записях. |
|- valign="top" | |- valign="top" | ||
|Пользователь имеет несколько баз между которыми необходим полный обмен информацией (репликация). | |Пользователь имеет несколько баз между которыми необходим полный обмен информацией (репликация). | ||
| − | |Замены внешней утилиты репликации. Разрешения конфликтов в автоматическом и/или ручном режиме. | + | |Замены внешней утилиты репликации. Передачи только инкремента данных. Разрешения конфликтов в автоматическом и/или ручном режиме. |
|} | |} | ||
| Строка 65: | Строка 67: | ||
[[Изображение:Save_stream_2.png]] | [[Изображение:Save_stream_2.png]] | ||
| + | |||
| + | == Реализация == | ||
===Переработанный алгоритм сохранения в поток=== | ===Переработанный алгоритм сохранения в поток=== | ||
| Строка 70: | Строка 74: | ||
Нам понадобятся следующие структуры данных: | Нам понадобятся следующие структуры данных: | ||
| − | + | {|border="1" style="border-collapse:collapse;" valign="top" cellpadding="2" | |
| − | + | |width="80px"|BO | |
| − | + | |Список (пул) бизнес-объектов; | |
| + | |- valign="top" | ||
| + | |CL | ||
| + | |Список клиент-датасетов, где будет храниться информация бизнес-объектов. Списки BO и CL содержат всегда одинаковой количество элементов. Бизнес объекту с номером N из списка BO соответствует клиент-датасет с таким же номером из списка CL. | ||
| + | |- valign="top" | ||
| + | |L | ||
| + | |Список идентификаторов записей, помещенных в поток. | ||
| + | |- valign="top" | ||
| + | |Q | ||
| + | |Список с номерами объектов из пула BO, показывающий очередность их помещения в поток. | ||
| + | |} | ||
| + | |||
| + | Концептуально, алгоритм сохранения в поток выглядит следующим образом: | ||
| + | |||
| + | # Вызывается метод SaveToStream2, куда передается: | ||
| + | ## поток для записи данных; | ||
| + | ## список закладок, если надо сохранить выделенные пользователем записи. Список можно не указывать, тогда то, какие записи будут сохранены, определяется четвертым параметром; | ||
| + | ## детальный датасет (если есть). Изначально передача детального датасета предназначалась для копирования таких сущностей, как накладная, где мы должны скопировать шапку (мастер) и позиции (детальный датасет). Но для любой сущности могут появиться дополнительные информационные таблицы (бизнес-объект -- справочник пользователя), т.е. таблицы связанные 1-1, которые также необходимо скопировать. Мы решали эту проблему в коде дублирования записи; | ||
| + | ## флаг сохранять все записи или только текущую. | ||
| + | # В зависимости от настроек внутри метода организуется цикл по записям (выделенным или всем) или обрабатывается только текущая запись. | ||
| + | # Для каждой записи вызывается метод _SaveToStream2, куда передается: | ||
| + | ## Идентификатор записи; | ||
| + | ## Тип и подтип записи; | ||
| + | # Метод _SaveToStream2 проверяет в списке L не был ли сохранен уже объект с таким идентификатором. Если такой объект уже был сохранен, то метод завершает свое выполнение. | ||
| + | # Проверяем наличие RUID у объекта. Если нет, то формируем его. | ||
| + | # Если объект еще не сохранялся, то проверяется пул BO на наличие объекта нужного нам класса и подтипа. Если нашли, то берем его номер. Если нет, то создаем объект и помещаем в пул. В соответствие этому объекту создаем клиент-датасет и помещаем его в список CL. Бизнес объекту устанавливаем SubSet=ByID. Присваиваем идентификатор и открываем бизнес объект. Если датасет пуст, то имеем ошибку о чем и сигнализируем с помощью исключения. | ||
| + | # Записываем в список L идентификатор сохраняемого объекта, а в список Q -- номер объекта в списке BO. | ||
| + | # Добавляем запись в сопоставленный клиент-датасет из списка CL и заполняем поля значениями полей бизнес-объекта. | ||
| + | |||
| + | === Writer -- объект для записи данных === | ||
| + | |||
| + | В существующем алгоритме, код записи информации в поток перемешан с кодом формирования данных для записи. Планируется, отделить его, выделив отдельный абстрактный класс Writer, от которого будут наследоваться BinaryStreamWriter, XMLWriter, TextWriter. | ||
| + | |||
| + | == Тестирование == | ||
| + | |||
| + | В основу методики тестирования положено сравнение между собой двух баз, основанных на единой, третьей, исходной базе. | ||
| + | |||
| + | # Сначала подготавливается исходная база. Это может быть либо совершенно чистый эталон, либо база с загруженными настройками, либо произвольная база с настройками и данными. | ||
| + | # Далее, делаются две копии этой базы: A и B. | ||
| + | # На базе А создаются объекты данных, которые затем сохраняются в поток и записываются в дисковый файл. | ||
| + | # Данный файл загружается на базу B. | ||
| + | # По окончании загрузки базы сравниваются между собой (например, с помощью утилиты сравнения данных программы IBExpert). Работа алгоритма сохранения в поток считается корректной, если результирующие базы идентичны между собой за исключением значений первичных ключей. | ||
| + | |||
| + | Тестирование одно/двунаправленной репликации между N базами осуществляется аналогичным образом. По окончании полного круга репликации все N баз должны быть идентичны между собой. | ||
| + | |||
| + | Подлежит тестированию: | ||
| + | |||
| + | * Сохранение простого одинарного объекта (одна запись в таблице без внешних ссылок). | ||
| + | * Сохранение нескольких объектов одного типа. | ||
| + | * Сохранение нескольких древовидных объектов. Сохраняются элементы, промежуточные в иерархии, проверяется сохранение родительских и вложенных элементов. | ||
| + | * Сохранение данных следующих типов: целое число (короткое и длинное), число с фиксированной точкой, число с плавающей точкой, строка, дата, время, дата и время, двоичный объект. Для строки проверяется корректность сохранения в случае содержания символов: кавычка одинарная, кавычка двойная, знаки больше и меньше, а также проверяется сохранение символов кирилического алфавита. | ||
| + | * Сохранение циклических ссылок между двумя записями в двух таблицах. Например, компания и расчетный счет. | ||
| + | * Сохранение циклических ссылок между двумя записями в одной таблице. | ||
| + | * Сохранение циклических ссылок между тремя записями в трех разных таблицах. | ||
| + | * Сохранение документа с позициями. | ||
| + | * Сохранение группы документа с позициями. | ||
| + | * Сохранение записи и записи из таблицы, присоединенной один-к-одному. | ||
| + | * Сохранение записи и записей из N таблиц, присоединенных последовательно один-к-одному. Как минимум проверить при N = 2. | ||
| + | * Сохранение записи с атрибутами типа множество. Проверить, когда во множестве: ноль, один и несколько элементов. Проверить ситуацию, когда таблица-связка кроме двух ключей содержит еще и дополнительные данные. | ||
| + | * Сохранение не менее миллиона записей разных типов. Проверить, взяв за основу реальную базу данных размером больше 10 Гб. В этом случае получение базы B осуществить следующим образом: взять базу с данными. Сделать ее копию. Определить объекты для переноса и удалить их с копии. Перенести объекты с первой базы на вторую. Сравнить базы. | ||
| + | |||
| + | Необходимо также проверить идентичность работы старого алгоритма сохранения в поток и нового. Для этого: | ||
| + | |||
| + | # Берем эталонную базу с комплексной автоматизацией. | ||
| + | # Сохраняем с нее все настройки используя старый алгоритм. | ||
| + | # Сохраняем с нее все настройки используя новый алгоритм. | ||
| + | # Загружаем настройки на эталон старым алгоритмом. | ||
| + | # Загружаем настройки на эталон новым алгоритмом. | ||
| + | # Сравниваем две базы. | ||
| + | Все процессы по тестированию должны быть автоматизированы и выполняться с помощью макросов, написанных на Гедымине. | ||
| − | |||
| − | [[Category:Постановка]] | + | [[Category:Постановка-Сделано]] |
| + | [[Category:Репликация]] | ||
Текущая версия на 19:24, 4 января 2013
Требования к новому алгоритму сохранения в поток были первоначально сформированы в результате дискуссии на сайте gsbelarus.com:
- Увеличение скорости минимум в 10 раз;
- Уменьшение размера файла минимум в 10 раз (при использовании двоичного формата);
- Возможность сохранения в дфоичном формате, в тексте и в XML;
- Предусмотреть возможность сохранения только объектов измененных после указанной даты;
- Предусмотреть возможность инкрементного сохранения объектов;
- Предусмотреть возможность расширенного и краткого отображения информации о ходе процесса. Дать пользователю возможность прервать процесс в любой момент времени;
- Предусмотреть возможность запуска процесса из командной строки;
- Предусмотреть возможность сохранения всей базы данных в потоке;
- Процедура должна обрабатывать миллион записей на компьютере с 512 Мб оперативной памяти за приемлемое время;
- Формирование потока данных и загрузка его на базу должна осуществляться не в монопольном режиме.
- Предусмотреть возможность блокировки на изменение записей, переданных на другую базу.
- Реализовать корректный механизм замены и объединения данных объектов.
См. сравнение механизмов репликации и сохранения данных в поток в статье Сохранение в поток и репликация.
Содержание |
[править] Сценарии использования сохранения в поток
| Сценарий | Чего хотим добиться |
|---|---|
| Пользователь выбирает объект или группу объектов и сохраняет их в поток. | Минимум десятикратного ускорения по сравнению с действующим алгоритмом. Меньшего размера файла. Контроля над ходом процесса. Возможности прервать процесс в любой момент времени. |
| Пользователь указывает сохранить в поток объекты, измененные после указанной даты. | Аналогично предыдущему. Система производит в базе данных поиск всех объектов, измененных после указанной даты (как быть со множествами?). |
| Разработчик сохраняет настройку в формате XML. | Текстовый файл, содержащий настройку ввиде форматированного XML, можно сравнить с прежней версией настройки и таким образом определить что было изменено. Такие настройки можно помещать в хранилище StarTeam и использовать систему контроля версий. |
| Пользователь производит загрузку потока на базу данных. | Ускорения процесса. Контроля над ходом выполнения и возможности прервать процесс в любой момент времени. Внятного разрешения конфликтных ситуаций: Обновлять записи всегда, Обновлять записи только если они новее, чем те, что находятся в базе данных, Пропускать записи. Возможности выставить действие по-умолчанию как для всего процесса, так и для объектов конкретного типа. Возможности сравнивать данные объектов при возникновении конфликта перезаписи уже существующего объекта. Возможности слияния данных двух объектов (подобно той, которая существует в механизме объединения двух записей). |
| Пользователь имеет головную базу и несколько перефирийных, на которых происходит редактирование данных. Периодически данные с перефирийных баз передаются на головную для консолидации, причем изменения от головной базы данных не передаются на перефирийные и изменения от одной перефирийной базы данных не передаются на другую. | Возможности инкрементной передачи данных. Т.е. перадаваться должны только объекты измененные (добавленные) с момента последней передачи. Возможности передавать информацию об удаленных записях. |
| Пользователь имеет несколько баз между которыми необходим полный обмен информацией (репликация). | Замены внешней утилиты репликации. Передачи только инкремента данных. Разрешения конфликтов в автоматическом и/или ручном режиме. |
[править] Увеличение скорости
Беглый анализ показывает, что основной проблемой существующего сохранения является использование рекурсии и бизнес объектов. Сейчас работает так:
- начинаем сохранять запись определенного типа (запись бизнес-объекта);
- создаем клиент датасет и переносим в него данные полей сохраняемой записи;
- записываем в поток служебную информацию и данные клиент датасета;
- находим поля-ссылки, создаем экземпляры бизнес-объектов соответствующего типа и рекурсивно вызываем процедуру сохранения в поток, т.е. переходим к п. 1.
Таким образом, в процессе сохранения объект одного и того же типа может создаваться неограниченное число раз.
[править] Почему использование бизнес-объекта замедляет процесс?
- Бизнес-объект является наследником от класса TIBDataSet и уже в силу этого он медленее при обращении к данным чем легковесный TIBSQL;
- Формирование, последующий парсинг и переформирование запроса бизнес-объекта занимают значительное время;
- При создании экземпляра бизнес-объекта в скрипт-контрол загружаются скрипт-функции перекрытых методов;
Использование пула объектов сведет к минимуму затраты по первым двум пунктам, но проблема отключения макросов для конкретного объекта остается не решенной.
[править] Уменьшение размера файла
Уменьшения размера файла мы добьемся за счет отказа от рекурсии при формировании потока данных из-за которой мы имеем следующую внутреннюю структуру файла:
Служебная информация и заголовок датасета записываются практически перед каждой записью, что существенно раздувает файл. В новом формате, записи одного типа будут сгруппированы:
[править] Реализация
[править] Переработанный алгоритм сохранения в поток
Нам понадобятся следующие структуры данных:
| BO | Список (пул) бизнес-объектов; |
| CL | Список клиент-датасетов, где будет храниться информация бизнес-объектов. Списки BO и CL содержат всегда одинаковой количество элементов. Бизнес объекту с номером N из списка BO соответствует клиент-датасет с таким же номером из списка CL. |
| L | Список идентификаторов записей, помещенных в поток. |
| Q | Список с номерами объектов из пула BO, показывающий очередность их помещения в поток. |
Концептуально, алгоритм сохранения в поток выглядит следующим образом:
- Вызывается метод SaveToStream2, куда передается:
- поток для записи данных;
- список закладок, если надо сохранить выделенные пользователем записи. Список можно не указывать, тогда то, какие записи будут сохранены, определяется четвертым параметром;
- детальный датасет (если есть). Изначально передача детального датасета предназначалась для копирования таких сущностей, как накладная, где мы должны скопировать шапку (мастер) и позиции (детальный датасет). Но для любой сущности могут появиться дополнительные информационные таблицы (бизнес-объект -- справочник пользователя), т.е. таблицы связанные 1-1, которые также необходимо скопировать. Мы решали эту проблему в коде дублирования записи;
- флаг сохранять все записи или только текущую.
- В зависимости от настроек внутри метода организуется цикл по записям (выделенным или всем) или обрабатывается только текущая запись.
- Для каждой записи вызывается метод _SaveToStream2, куда передается:
- Идентификатор записи;
- Тип и подтип записи;
- Метод _SaveToStream2 проверяет в списке L не был ли сохранен уже объект с таким идентификатором. Если такой объект уже был сохранен, то метод завершает свое выполнение.
- Проверяем наличие RUID у объекта. Если нет, то формируем его.
- Если объект еще не сохранялся, то проверяется пул BO на наличие объекта нужного нам класса и подтипа. Если нашли, то берем его номер. Если нет, то создаем объект и помещаем в пул. В соответствие этому объекту создаем клиент-датасет и помещаем его в список CL. Бизнес объекту устанавливаем SubSet=ByID. Присваиваем идентификатор и открываем бизнес объект. Если датасет пуст, то имеем ошибку о чем и сигнализируем с помощью исключения.
- Записываем в список L идентификатор сохраняемого объекта, а в список Q -- номер объекта в списке BO.
- Добавляем запись в сопоставленный клиент-датасет из списка CL и заполняем поля значениями полей бизнес-объекта.
[править] Writer -- объект для записи данных
В существующем алгоритме, код записи информации в поток перемешан с кодом формирования данных для записи. Планируется, отделить его, выделив отдельный абстрактный класс Writer, от которого будут наследоваться BinaryStreamWriter, XMLWriter, TextWriter.
[править] Тестирование
В основу методики тестирования положено сравнение между собой двух баз, основанных на единой, третьей, исходной базе.
- Сначала подготавливается исходная база. Это может быть либо совершенно чистый эталон, либо база с загруженными настройками, либо произвольная база с настройками и данными.
- Далее, делаются две копии этой базы: A и B.
- На базе А создаются объекты данных, которые затем сохраняются в поток и записываются в дисковый файл.
- Данный файл загружается на базу B.
- По окончании загрузки базы сравниваются между собой (например, с помощью утилиты сравнения данных программы IBExpert). Работа алгоритма сохранения в поток считается корректной, если результирующие базы идентичны между собой за исключением значений первичных ключей.
Тестирование одно/двунаправленной репликации между N базами осуществляется аналогичным образом. По окончании полного круга репликации все N баз должны быть идентичны между собой.
Подлежит тестированию:
- Сохранение простого одинарного объекта (одна запись в таблице без внешних ссылок).
- Сохранение нескольких объектов одного типа.
- Сохранение нескольких древовидных объектов. Сохраняются элементы, промежуточные в иерархии, проверяется сохранение родительских и вложенных элементов.
- Сохранение данных следующих типов: целое число (короткое и длинное), число с фиксированной точкой, число с плавающей точкой, строка, дата, время, дата и время, двоичный объект. Для строки проверяется корректность сохранения в случае содержания символов: кавычка одинарная, кавычка двойная, знаки больше и меньше, а также проверяется сохранение символов кирилического алфавита.
- Сохранение циклических ссылок между двумя записями в двух таблицах. Например, компания и расчетный счет.
- Сохранение циклических ссылок между двумя записями в одной таблице.
- Сохранение циклических ссылок между тремя записями в трех разных таблицах.
- Сохранение документа с позициями.
- Сохранение группы документа с позициями.
- Сохранение записи и записи из таблицы, присоединенной один-к-одному.
- Сохранение записи и записей из N таблиц, присоединенных последовательно один-к-одному. Как минимум проверить при N = 2.
- Сохранение записи с атрибутами типа множество. Проверить, когда во множестве: ноль, один и несколько элементов. Проверить ситуацию, когда таблица-связка кроме двух ключей содержит еще и дополнительные данные.
- Сохранение не менее миллиона записей разных типов. Проверить, взяв за основу реальную базу данных размером больше 10 Гб. В этом случае получение базы B осуществить следующим образом: взять базу с данными. Сделать ее копию. Определить объекты для переноса и удалить их с копии. Перенести объекты с первой базы на вторую. Сравнить базы.
Необходимо также проверить идентичность работы старого алгоритма сохранения в поток и нового. Для этого:
- Берем эталонную базу с комплексной автоматизацией.
- Сохраняем с нее все настройки используя старый алгоритм.
- Сохраняем с нее все настройки используя новый алгоритм.
- Загружаем настройки на эталон старым алгоритмом.
- Загружаем настройки на эталон новым алгоритмом.
- Сравниваем две базы.
Все процессы по тестированию должны быть автоматизированы и выполняться с помощью макросов, написанных на Гедымине.

