Re[30]: Объектные базы как они есть
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 19.04.05 14:42
Оценка:
Здравствуйте, GlebZ, Вы писали:

GZ>Здравствуйте, eao197, Вы писали:


GZ>>>В данном случае мы подразумеваем, что можем выловить некорректную ситуацию (независимо от типа доступа) еще на уровне обработки метаданных. Но если у нас метаданные не затронуты. В результате мы получаем запрос, в котором мы должна учитывать, что информация о удаленной ссылки не лежит именно в данном объекте. Там проблемы начнутся нехилые.


E>>Я думаю, что здесь проблем нет. Просто такая обработка лежит на отдельном уровне абстракции. Где-то выше кэша, но ниже планировщика запросов (или какая там архитектура будет).

GZ>Смотри что получается. У нас есть запрос вместе с where exist(object.reference) Три варианта:
GZ>1. Мы просматриваем объект на который ссылаемся. Плохо. Избыточное чтение.
GZ>2. Мы кладем это в запрос. Плохо. В результате у нас получается очень неприятное условие и длинное.(в ОРМ — более чем криминально, но для ООДБ этот вариант я считаю наименее плохим)
GZ>3. Мы смотрим после выполнения запроса. Плохо. Избыточное чтение.

Торможу что-то к вечеру. Давай еще раз. Вот так я себе представлял объект-ссылку:
class    One_side
{
    ref< Another_side > m_ref;
}

class Another_side
{
    ref< One_side > m_ref
}

// А это физическое представление ссылки.
class    Ref_image
{
    bool    m_is_valid;
    oid    m_one_side;
    oid    m_another_side;
}


Когда в объекте One_size обнулятся ссылка One_side.m_ref в соответствующем объекте Ref_image сбрасывается флаг m_is_valid.
Когда каким-то образом Another_side извлекается из БД, сама СУБД автоматически тянет объект Ref_image и проверяет его m_is_valid. Если m_is_valid сброшен, то в Another_side автоматически обнуляется m_ref. И только после этого Another_side идет в дальнейшую обработку на стороне СУБД. Т.е., в моем представлении такими вещами должен заниматься уровень сериализации.

Проблемы в таком подходе, имхо, возникают, если объектиков Ref_image будет куча. Т.е. возврат к тому вопросу, с которого stalcer начинал.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[31]: Объектные базы как они есть
От: GlebZ Россия  
Дата: 19.04.05 15:29
Оценка:
Здравствуйте, eao197, Вы писали:

E>Торможу что-то к вечеру.

Я тоже сейчас не Энштейн.
E>Давай еще раз. Вот так я себе представлял объект-ссылку:
E>
E>class    One_side
E>{
E>    ref< Another_side > m_ref;
E>}

E>class Another_side
E>{
E>    ref< One_side > m_ref
E>}

E>// А это физическое представление ссылки.
E>class    Ref_image
E>{
E>    bool    m_is_valid;
E>    oid    m_one_side;
E>    oid    m_another_side;
E>}
E>


E>Когда в объекте One_size обнулятся ссылка One_side.m_ref в соответствующем объекте Ref_image сбрасывается флаг m_is_valid.

E>Когда каким-то образом Another_side извлекается из БД, сама СУБД автоматически тянет объект Ref_image и проверяет его m_is_valid. Если m_is_valid сброшен, то в Another_side автоматически обнуляется m_ref. И только после этого Another_side идет в дальнейшую обработку на стороне СУБД. Т.е., в моем представлении такими вещами должен заниматься уровень сериализации.
Возможно я тоже чего-то не врубился. Но я описывал ситуацию, в которой удаляется сам объект. Приведу слова Alexey Rovdo:

Если после поднятия ссылки (уже в другой задаче) оказывается, что она указывает на помеченный как удаленный элемент, то без уведомления приложения СУБД сама может обнулить соответсвующую ссылку и передать дальше уже null, а объект на диске исправить (вписать нул в хначение ссылки).

Или я чего-то не понял?

E>Проблемы в таком подходе, имхо, возникают, если объектиков Ref_image будет куча. Т.е. возврат к тому вопросу, с которого stalcer начинал.

Именно. Либо мы начинаем обнулять (или приводить в состояние удален) ссылки при удалении объекта (по типу как ты ты привел), или мы получаем то, что я описал.

С уважением, Gleb.
... << RSDN@Home 1.1.4 beta 4 rev. 358>>
Re[32]: Объектные базы как они есть
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 19.04.05 15:53
Оценка: +1
Здравствуйте, GlebZ, Вы писали:

GZ>Возможно я тоже чего-то не врубился. Но я описывал ситуацию, в которой удаляется сам объект. Приведу слова Alexey Rovdo:

GZ>

GZ>Если после поднятия ссылки (уже в другой задаче) оказывается, что она указывает на помеченный как удаленный элемент, то без уведомления приложения СУБД сама может обнулить соответсвующую ссылку и передать дальше уже null, а объект на диске исправить (вписать нул в хначение ссылки).

GZ>Или я чего-то не понял?

Вообще-то я думал, что мы говорим о ссылках вот в этом контексте Re[16]: Объектные базы как они есть
Автор: eao197
Дата: 18.04.05
:

S>Так вот, например, я загрузил операцию (или мне ее вернула какая-нибудь функция) и решил изменить у нее ссылку на документ. То есть переприсвоить операцию другому документу (пример, конечно неудачный, но...). Я же должен соответствующие изменения сделать и в коллекциях ссылок старого и нового документа. Т.е. все равно эти коллекции сначала придется подгрузить. Так что выделяй в отдельный объект или нет — без разницы.

Что-то я не очень понимаю в чем суть проблемы. Если по условиям задачи возможно, что в объекте "операция над документом" можно поменять ссылку на изменяемый документ (что само по себе странно), то можно организовать коллекцию ссылок таким образом, чтобы операции вставки/удаления были дешевыми. Например, вместо вектора ссылок использовать двусвязный список (каждый элемент содержит собственно ссылку + ссылки на предыдущий/следующий элементы списка) или map на основе B+ дерева.

И выше по ветви.
Речь шла об объекте-документе, у которого есть список ссылок на операции над документом. И необходимо для одной операции поменять ссылку на документ. Т.е. пока ничего не удаляется, а изменяется ссылка. Хотя тоже самое может происходить, если в моем последнем примере с One_side, Another_side, какой-то из объектов будет удален.

E>>Проблемы в таком подходе, имхо, возникают, если объектиков Ref_image будет куча. Т.е. возврат к тому вопросу, с которого stalcer начинал.

GZ>Именно. Либо мы начинаем обнулять (или приводить в состояние удален) ссылки при удалении объекта (по типу как ты ты привел), или мы получаем то, что я описал.

Да, ты прав.
Но я смотрю на это так. У нас есть несколько объектов между которыми установлены двунаправленные связи. Удаляя один объект изменяя его ссылки мы все равно должны будем поменять ссылки на другой строне связи. И при любом подходе суммарное время на корректировку ссылок будет приблизительно одинаковым. Но, если мы корректируем ссылки сразу при удалении объекта, мы делаем операцию удаления заведомо длительной. Если же мы корректируем ссылки при первом доступе к объекту на другой стороне связи, мы увеличиваем время доступа к нему. Но это время может быть значительно меньше, чем нам потребовалось бы на удаление с полной корректировкой ссылок. Т.е. в варианте с отложенной корректировкой мы как бы амортизируем время небольшим увеличением времени доступа к объектам.

Хорошо это или нет?
Наверное зависит от задачи.
Возможно, хорошо было бы говорить ООСУБД как именно ей следует поступать в конкретном случае.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[30]: Объектные базы как они есть
От: Sinclair Россия https://github.com/evilguest/
Дата: 19.04.05 15:57
Оценка:
Здравствуйте, GlebZ, Вы писали:

GZ>Тут несколько другой GC. Второй тип ссылочной целостности, в котором при удалении объекта — все ссылки на него обнуляются. Хотя в принципе это можно организовать более простым способом чем в goods. При наличии метаданных, ессно.

Это скорее не GC, а метафора слабой ссылки — weak reference. По моему скромному имху, ООСУБД должна предоставлять оба типа ссылок. Чтобы не принуждать владельца любой ссылки к постоянной проверке ее валидности, и в то же время не рисковать "пришпилить" мусор при помощи невинной записи в логе или еще чего нибудь.
Кстати, если реализовывать эту метафору в стиле .Net, т.е. предоставить единственную реализацию класса слабой ссылки, то можно существенно улучшить производительность обнуления. Благодаря тому, что вся семантика этого класса совершенно точно известна еще при проектировании СУБД, можно схитрить при синхронном обнулении ссылок и не поднимать в память "честные" объекты, ограничившись прямой модификацией дисковых страниц. Кроме того, можно использовать кластеризацию по target ссылки, благодаря чему обнуление затронет минимум страниц (а с учетом потрясающей компактности этих ссылок много страниц потребуется обновлять только при удалении очень популярных объектов).
Не хуже решается и вопрос асинхронного обнуления — проверить содержащийся OID на валидность при каждом снятии ссылки не так уж и дорого. Единственное но — обращение к Target, которое на первый взгляд не должно вызывать побочных эффектов, в такой системе все-таки "трогает" ссылку, со всеми вытекающими последствиями для транзакции, читающей эту ссылку.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[31]: Объектные базы как они есть
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 19.04.05 16:07
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, GlebZ, Вы писали:


GZ>>Тут несколько другой GC. Второй тип ссылочной целостности, в котором при удалении объекта — все ссылки на него обнуляются. Хотя в принципе это можно организовать более простым способом чем в goods. При наличии метаданных, ессно.

S>Это скорее не GC, а метафора слабой ссылки — weak reference. По моему скромному имху, ООСУБД должна предоставлять оба типа ссылок. Чтобы не принуждать владельца любой ссылки к постоянной проверке ее валидности, и в то же время не рисковать "пришпилить" мусор при помощи невинной записи в логе или еще чего нибудь.

Я когда-то делал два типа ссылок: soft_ref и hard_ref. Объясню на примерах. Пусть объект A ссылается на объект B с помощью seft_ref, а объект C ссылается на объект D с помощью hard_ref. Объекты B и D не могут быть удалены, пока существуют объекты A и C. Если же удаляется объект A, то объект B остается в базе, просто для него уменьшается счетчик ссылок. Если же удаляется объект C, то с ним вместе удаляется и объект D (при условии, что на него кроме A больше никто не ссылается). Т.е. hard_ref -- это отношение владения (D без С не может существовать), а soft_ref -- это соседские отношения.

Sinclair, это не возражение против твоего поста. Просто я разсказал, как я когда-то делал.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Ссылки всякие нужны, ссылки всякие важны
От: Sinclair Россия https://github.com/evilguest/
Дата: 19.04.05 16:45
Оценка: 4 (1)
Здравствуйте, eao197, Вы писали:

E>Я когда-то делал два типа ссылок: soft_ref и hard_ref. Объясню на примерах. Пусть объект A ссылается на объект B с помощью seft_ref, а объект C ссылается на объект D с помощью hard_ref. Объекты B и D не могут быть удалены, пока существуют объекты A и C. Если же удаляется объект A, то объект B остается в базе, просто для него уменьшается счетчик ссылок. Если же удаляется объект C, то с ним вместе удаляется и объект D (при условии, что на него кроме A больше никто не ссылается). Т.е. hard_ref -- это отношение владения (D без С не может существовать), а soft_ref -- это соседские отношения.

Фактически, это третий тип ссылок. Трабл с ним я вижу в том, что не вполне понятно, что произойдет в случае наличия еще и soft_ref ссылок на объект D. Понятно, что само наличие двух hard_ref ссылок на один объект в такой системе — косяк. А вот что делать с софт ссылками — непонятно.
Мы в свое время делали сборку мусора на основе подсчета ссылок. В ней удаление объекта взводило флаг "удален", после чего создание новых ссылок на него было запрещено, и уменьшало счетчик на единичку. Для нового объекта количество ссылок ставилось в единичку. При достижении нулевого количества ссылок объект удалялся из БД.
С философской точки зрения, это эквивалентно внесению в традиционную технологию refcount концепции "внешнего наблюдателя". При создании объекта внешний наблюдатель как бы говорит: "я за тобой слежу". Выполняя удаление объекта, наблюдатель говорит "я перестал за тобой следить". Естественно, основная проблема концепции refcount — повисание циклов — сохранялась. Я пока что забил на вопросы управления временем жизни объектов в ООСУБД, хотя практика управляемых сред показывает рулезность GC и недетерминистической финализации по сравнению со всем остальным. Так что с моей точки зрения, самой "правильной" реализацией должна быть именно поддержка автоматического GC на основе достижимости объектов, модифицированная присутствием "внешнего наблюдателя". Эта модификация необходима, чтобы свежесозданные объекты не умирали самопроизвольно, продолжая оставаться доступными при помощи ассоциативного доступа. Хотя, с учетом наблюдения, сделанного сталкером
Автор: stalcer
Дата: 12.04.05
, о необходимости <i>явной</i> публикации объектов для ассоциативного поиска
Автор: stalcer
Дата: 13.04.05
, внешнего наблюдателя можно и не вводить. Т.е. помечая объект как доступный для поиска при помощи включения его в коллекцию, мы гарантируем его выживание благодаря наличию ссылки.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[33]: Объектные базы как они есть
От: GlebZ Россия  
Дата: 19.04.05 16:49
Оценка: +1
Здравствуйте, eao197, Вы писали:

E>Но я смотрю на это так. У нас есть несколько объектов между которыми установлены двунаправленные связи. Удаляя один объект изменяя его ссылки мы все равно должны будем поменять ссылки на другой строне связи. И при любом подходе суммарное время на корректировку ссылок будет приблизительно одинаковым. Но, если мы корректируем ссылки сразу при удалении объекта, мы делаем операцию удаления заведомо длительной. Если же мы корректируем ссылки при первом доступе к объекту на другой стороне связи, мы увеличиваем время доступа к нему. Но это время может быть значительно меньше, чем нам потребовалось бы на удаление с полной корректировкой ссылок. Т.е. в варианте с отложенной корректировкой мы как бы амортизируем время небольшим увеличением времени доступа к объектам.

Тут IMHO не все так однозначно. Изменение ссылки точно такая-же логгируемая операция, как и любое изменение объекта. То есть, при изменении, мы должны записать об этом в конце транзакции в лог. Попробуем рассмотреть оба варианта с точки зрения работы лога и транзакций.
В первом случае мы получаем, что при окончании транзакции мы сохраняем записи всем скопом в лог, и у нас при этом они кладуться в одну или несколько последовательных страниц.
Во втором случае, у нас в случае если транзакция read-only, мы вынуждены открыть ее (а я думаю лучше по соседству другую) как updatable. Но при этом, непонятна длительность этой транзакции, и количество данных которое должно быть сохранено существенно меньше чем размер страницы.

С уважением, Gleb.
... << RSDN@Home 1.1.4 beta 4 rev. 358>>
Re: Ссылки всякие нужны, ссылки всякие важны
От: GlebZ Россия  
Дата: 19.04.05 17:32
Оценка:
Здравствуйте, Sinclair, Вы писали:

Ну и я пожалуй внесу свою лепту. Когда-то хотел (и сейчас хочу) сделать некоторую фичу для ORM.
В объект введено состояние логически удален. Вообще, удивительно. Это настолько часто используется в бизнес-приложениях, но ни одна тулза (известная мне) не предоставляет средств (кроме каких-то визуальных тулзов для Delphi).
И к этому присобачена разного вида ссылки и такая проверка ссылочной целостности при удалении.
Тип ссылки 1. Если существует объект на который ссылается, то объект не может быть удален.
Тип ссылки 2. Если существует объект на который ссылается, то объект может быть удален только логически
Тип ссылки 3. Если существует объект на который ссылается, то оба объекта удаляются вместе (логически или физически)

Поскольку при этом поднимается некий граф объектов, то скорости тут ждать не приходится. Но для обычных бизнес-приложений, скорость должна быть достаточна.

С уважением, Gleb.
... << RSDN@Home 1.1.4 beta 4 rev. 358>>
Re[13]: Объектные базы как они есть
От: vdimas Россия  
Дата: 19.04.05 17:33
Оценка: 1 (1)
Здравствуйте, stalcer, Вы писали:

S>И еще один хитрый вопрос — должны ли связи быть частью объекта, или же они должны быть отдельными сущностями, возможно (а может и нет) отдельно грузиться, отдельно сохраняться, а самое главное — отдельно объявляться.


Кстати, в текущем проекте мы пришли именно к тому, что все связи — это беззаговорочно отдельные сущности. Если в некоем объекте есть колллекция других подчиненных объектов, то это реализовано как свойство-фасад (типа ICollection), делегирующее функциональность к выделенной сущности-линку.
Re[2]: Ссылки всякие нужны, ссылки всякие важны
От: Sinclair Россия https://github.com/evilguest/
Дата: 19.04.05 17:53
Оценка:
Здравствуйте, GlebZ, Вы писали:

GZ>В объект введено состояние логически удален.

Это состояние случайно не влечет за собой запрет ставить новые ссылки на этот объект?
GZ>Вообще, удивительно. Это настолько часто используется в бизнес-приложениях, но ни одна тулза (известная мне) не предоставляет средств (кроме каких-то визуальных тулзов для Delphi).
GZ>И к этому присобачена разного вида ссылки и такая проверка ссылочной целостности при удалении.
GZ>Тип ссылки 1. Если существует объект на который ссылается, то объект не может быть удален.
GZ>Тип ссылки 2. Если существует объект на который ссылается, то объект может быть удален только логически
GZ>Тип ссылки 3. Если существует объект на который ссылается, то оба объекта удаляются вместе (логически или физически)
Че-то я уже начинаю тормозить. Завтра перечитаю
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[14]: Объектные базы как они есть
От: vdimas Россия  
Дата: 19.04.05 17:55
Оценка:
Здравствуйте, Serginio1, Вы писали:

S>Здравствуйте, vdimas, Вы писали:



V>>Я же русским языком сказал, что в ячейках хеш-таблицы хранятся сортированные индексы, в которых всегда поиск NLog(N).

V>>Я все-таки буду писать подобную хеш-таблицу для второго дотнета (нужна самим подобная), учитывая твое замечание, предусмотрю в конструкторе фабрику для создания сортированных индексов в ячейках таблицы. Т.е., если будут подозрения плохое хеширование, можно подать фабрику для B+ индексов в ячейках. По умолчанию будет простой сортированный массив, в котором опять же трудоемкость не более NLog(N).
S> Таких хэш таблиц много, но опять же ты упрешься в неопределенность размера индекса и в итоге получишь гибрид хэш таблицы с Б+ деревом в каждой ячейке. Б+ деревья сами по себе очень универсальны и особенно подходят для неопределенного размера. Другое дело, что для больших структур лучше делать Б+ дерево на их хэшах со сравнением при выборе диапозона поискового хэша с искомым значением.
S> Кстати разница в поиске не столь огромна для Б+ деревьев и хэш таблиц. На практике всего в 4 раза http://gzip.rsdn.ru/article/alg/tlsd.xml
Автор(ы): Сергей Смирнов (Serginio1)
Дата: 14.08.2004
Пример реализации двухуровневого массива с помощью нового средства С# — generics. Сравнение производительности различных реализаций сортированных списков.


Для моего "гибрида" я получал разницу в десятки раз. Это ощутимо и это причина пользовать именно ее.
На самом деле, если функция кеширования достаточно удачна (а я как разработчик практически всегда этого добиваюсь), то прирост быстродействия пропорционален двоичному логарифму размера хеш-таблицы. (по крайней мере, стремится к такой пропорциональности)

Далее, в подавляющем большинстве случаев у меня суррогатные ключи — это последовательность целых значений. Генератор ключей построен так, чот при удалении ключи не пропадают, а запоминаются в кеше и повторно применяются при следующих созданиях объектов. Т.е. при многократных удалениях/созданиях объектов у меня практически нет "дыр" в последовательности и мои хранилища являются иделальным вариантом для простейшей ф-ии кеширования X = key % cache_size.
Re[15]: Объектные базы как они есть
От: vdimas Россия  
Дата: 19.04.05 17:56
Оценка:
Здравствуйте, stalcer, Вы писали:

S>Здравствуйте, Sinclair, Вы писали:


S>Точно. Все верно описал.


S>Если речь идет о большой системе, если она модульная, и если пишется совместно многими программистами, то двунаправленные связи в домейн-модели, если они вшиты в доменные классы будут представлять из себя большой геморрой, так как будут вносить много зависимостей между модулями на логическом уровне доменной модели. И что самое противное — циклических зависимостей.


S>И вторая проблема, как ты правильно написал, если есть две подсистемы и их объекты никак не связаны, а связываются они только в третьей подсистеме, то велика вероятность, что эта связь в достаточно большом количестве подзадач задействована не будет и ее было бы неправильно засовывать в объекты, чисто с точки зрения производительности/памяти.


S>Вот и возникает мысль о том что объявлять связи нужно отдельно от классов доменных объектов. И даже может не только объявлять, но и кэшировать как-то в отдельных структурах, а не при помощи перекрестных ссылок (коллекций ссылок).

S>Только вот я тут думаю уже на протяжении полугода как бы это сделать. Уж больно все сложно получается. Так — что у меня крыша съезжает .

хе... а у нас вполне работает...

могу выложить чать инфраструктуры и пообсуждать:


В моей системе есть дестрипторы — которые суть описатели и фабрики объектов обпределенного типа,
есть storages — суть хранилища объектов, описываемых неким десткриптором,
есть линки, которые кешируют лишь факт наличия связи (все работает по lazy loading).

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

Вот кусок живой сущности (вернее — ропера):


    public class SoftwareIdentityImpl : EntityWrapper {
        ProductImpl _product;

        IDetailEntitiesCollection _incarnations;
        IDetailEntitiesCollection _packages;
        IDetailEntitiesCollection _prerequisiteChecks;

        /// <summary>
        /// Creates new instance of software identity
        /// </summary>
        /// <param name="product">parent product</param>
        /// <param name="entityRef">SW ID entity object</param>
        public SoftwareIdentityImpl(ProductImpl product, IEntityRef entityRef)
            : base(EsdDb.SoftwareIdentity, entityRef) {
            _product = product;
            Init();
        }

        /// <summary>
        /// Constructed from existing SoftwareIdentity
        /// </summary>
        /// <param name="entityRef">SW ID entity object</param>
        public SoftwareIdentityImpl(IEntityRef entityRef)
            : base(EsdDb.SoftwareIdentity, entityRef) {
            Init();
        }

        /// <summary>
        /// Creates new SoftwareIdentity object for given product
        /// </summary>
        public SoftwareIdentityImpl(ProductImpl product)
            : base(EsdDb.SoftwareIdentity) {
            _product = product;
            Entity.productId = product.ObjectId;
            Init();
        }

        void Init() {
            _incarnations = EsdDb.Links.Version_Incarnation.GetDetail(Entity.ObjectId);
            _packages = EsdDb.Links.Version_Package.GetDetail(Entity.ObjectId);
            _prerequisiteChecks = EsdDb.Links.Version_Prerequisite.GetDetail(Entity.ObjectId);
        }


[...]


Обращаю внимание на метод Init данного враппера. В этом методе мы запрашиваем у объектов-линков специальные интерфейсы, через которые перечисляем подчиненные объекты.

Ниже приведены основные интерфейсы:

    /// <summary>
    /// Summary description for IEntityFactory.
    /// </summary>
    public interface IEntityFactory
    {
        /// <summary>
        /// Creates clone of entity
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        object CloneEntity(object entity);

        /// <summary>
        /// Creates uninitialized entity object
        /// </summary>
        /// <returns></returns>
        object CreateEntityInstance();

    }


    public interface IEntityDescriptor : IEntityFactory {

        /// <summary>
        /// TypeCode of Entity type
        /// </summary>
        TypeCodeT TypeCode { get; }

        /// <summary>
        /// Type of entity
        /// </summary>
        Type EntityType { get; }

        /// <summary>
        /// Type of wrapper
        /// </summary>
        Type WrapperType { get; }

        /// <summary>
        /// Short friendly entity name (most usual just class name without namespaces)
        /// </summary>
        string Name { get; }

        /// <summary>
        /// List of entity fields
        /// </summary>
        EntityFieldCollection FieldList { get; }

        /// <summary>
        /// Extracts entity ID
        /// </summary>
        /// <param name="entity">target entity</param>
        /// <returns>Object ID of entity</returns>
        ObjectIdT ExtractEntityId(object entity);

        /// <summary>
        /// Extracts entity Name
        /// </summary>
        /// <param name="entity">target entity</param>
        /// <returns>name of entity object</returns>
        string ExtractEntityName(object entity);

        /// <summary>
        /// Extracts entity description
        /// </summary>
        /// <param name="entity">target entity</param>
        /// <returns>description of entity object</returns>
        string ExtractEntityDescription(object entity);

        /// <summary>
        /// Creates wrapper for given entity instance
        /// </summary>
        /// <param name="entityRef">instance of entity ref to wrap</param>
        /// <returns>Wrapper object</returns>
        EntityWrapper GetWrapper(IEntityRef entityRef);

        /// <summary>
        /// Extracts NamedObjectId structure from entity object
        /// </summary>
        /// <param name="entity"></param>
        /// <returns>NamedObjectId entity representation</returns>
        NamedObjectId ToNamedObjectId(object entity);

        /// <summary>
        /// Extracts NamedObjectId structure from entity object
        /// </summary>
        /// <param name="entities">collection of entities</param>
        /// <returns>NamedObjectId[] array of entities representations</returns>
        NamedObjectId[] ToNamedObjectIdList(ICollection entities);

        EntityValue[] ConvertToEntitiesValues(ICollection entities);

        void SetFieldValue(object entity, int fieldId, Var val);

        Var GetFieldValue(object entity, int fieldId);

        /// <summary>
        /// Entity comparer
        /// </summary>
        IComparer Comparer { get; }

    }



    public interface IEntityStorage : IEntityRefFactory, ISynchronizable {

        /// <summary>
        /// Entity meta-information provider and helper
        /// </summary>
        IEntityDescriptor Descriptor { get; }

        /// <summary>
        /// Extracts full list of entities
        /// </summary>
        /// <returns>full list of entities</returns>
        ICollection GetEntityList();

        /// <summary>
        /// Extracts selected list of entity
        /// </summary>
        /// <param name="filterObjectIds">filtered IDs of entities</param>
        /// <returns>filtered list</returns>
        ICollection GetEntityList(ObjectIdT[] filterObjectIds);

        /// <summary>
        /// Get cache entry for entity ID.
        /// By default - with no cache behaviour implementation
        /// </summary>
        /// <param name="objectId">ID of entity</param>
        /// <param name="loadObject">if true the load object imediatelly</param>
        /// <returns>Cache entry for given entity ID</returns>
        IEntityRef GetCacheEntry(ObjectIdT objectId, bool loadObject);

        /// <summary>
        /// Get cache entry for entity
        /// By default - with no cache behaviour implementation
        /// </summary>
        /// <param name="entity">ID of entity</param>
        /// <returns>Cache entry for given entity ID</returns>
        IEntityRef GetCacheEntry(object entity);

        /// <summary>
        /// Get cache entries
        /// </summary>
        /// <param name="entityCollection"></param>
        /// <returns></returns>
        ICacheEntryCollection GetCacheEntries(ICollection entityCollection);


        /// <summary>
        /// Get cache entries
        /// </summary>
        /// <param name="ids">IDs of objects</param>
        /// <param name="initialize">initialize cache entry</param>
        /// <returns></returns>
        ICacheEntryCollection GetCacheEntries(ObjectIdT[] ids, bool initialize);

        /// <summary>
        /// Initializes cache entry if needed
        /// </summary>
        /// <param name="entry">cache</param>
        void InitCacheEntry(IEntityRef entry);

        /// <summary>
        /// Extract related objects from DB or cache
        /// </summary>
        /// <param name="childStorage">related links</param>
        /// <param name="parentObjId">master object ID</param>
        /// <returns>list of related objects</returns>
        ICollection GetChildEntities(IEntityStorage childStorage, ObjectIdT parentObjId);

        // TODO: Remove!!!
        ICollection GetChildEntities(TypeCodeT childTypeCode, ObjectIdT parentObjId);

        /// <summary>
        /// Creates new entity object in storage
        /// initializes key fields
        /// </summary>
        /// <returns></returns>
        IEntityRef CreateNewEntity();

        /// <summary>
        /// TODO: Remove!!!
        /// </summary>
        /// <param name="parentStorage"></param>
        /// <param name="masterObjectId"></param>
        /// <returns></returns>
        IEntityRef CreateRelatedEntity(IEntityStorage parentStorage, ObjectIdT masterObjectId);
            
        /// <summary>
        /// Deletes entity from storage
        /// </summary>
        /// <param name="entityId">id of entity</param>
        /// <param name="transaction">transaction context</param>
        void DeleteEntity(EsdTransaction transaction, ObjectIdT entityId);

        /// <summary>
        /// Save entity wrapper
        /// </summary>
        /// <param name="transaction"></param>
        /// <param name="wrapper"></param>
        void SaveEntityWrapper(EsdTransaction transaction, EntityWrapper wrapper);

        /// <summary>
        /// Collection of related IEntityRef entries
        /// </summary>
        /// <param name="link"></param>
        /// <param name="masterObjectId"></param>
        /// <returns></returns>
        ICollection GetRelatedEntities(IMasterDetailLink link, ObjectIdT masterObjectId);

        /// <summary>
        /// Register link on storage
        /// </summary>
        /// <param name="link"></param>
        void RegisterLink(LinkBase link);

        IMasterDetailLink GetMasterDetailLink(TypeCodeT childTypeCode);

    }

    /// <summary>
    /// Collection of IEntityRef
    /// </summary>
    public interface ICacheEntryCollection : ICollection {

        /// <summary>
        /// Storage
        /// </summary>
        IEntityStorage EntityStorage { get; }
        
        /// <summary>
        /// initialized tag
        /// </summary>
        bool Initialized { get; }
    }


    public interface IMasterDetailLink {
        void Clear();

        /// <summary>
        /// Master entity meta-info
        /// </summary>
        IEntityStorage MasterStorage { get; }

        /// <summary>
        /// Detail entity meta-info
        /// </summary>
        IEntityStorage DetailStorage { get; }


        /// <summary>
        /// Returns detail links
        /// </summary>
        /// <param name="masterObjectId">master object links</param>
        /// <returns>Detail links collection</returns>
        IDetailEntitiesCollection GetDetail(ObjectIdT masterObjectId);

    }

    /// <summary>
    /// Detail links bag definition
    /// </summary>
    public interface IDetailEntitiesCollection : ICollection, IEntityListProvider {
        /// <summary>
        /// add detail linked object
        /// </summary>
        /// <param name="childEntityRef">added child entity</param>
        void Add(IEntityRef childEntityRef);

        /// <summary>
        /// Key of Master Object (ObjectIdT)
        /// </summary>
        ObjectIdT MasterObjectId { get; }

        /// <summary>
        /// Master entity meta-info
        /// </summary>
        IEntityStorage MasterEntityStorage { get; }

        /// <summary>
        /// Detail entity meta-info
        /// </summary>
        IEntityStorage DetailEntityStorage { get; }

        /// <summary>
        /// Creates new detail-side linked (!!!) object
        /// </summary>
        /// <returns>newly created object</returns>
        IEntityRef CreateDetailEntity();

        /// <summary>
        /// Accesor to linked object by ID
        /// </summary>
        /// <param name = "detailObjectId">ID of linked object to extract</param>
        object this[ObjectIdT detailObjectId] { get; }

        /// <summary>
        /// Remove child object (or delete in pure MD-link)
        /// </summary>
        /// <param name="transaction"></param>
        /// <param name="childObjectId"></param>
        void RemoveChild(EsdTransaction transaction, ObjectIdT childObjectId);
    }


    public interface IEntityRef {
        ObjectIdT ObjectId { get; }
        object Entity { get; set; }
    }


    /// <summary>
    /// Entity reference
    /// </summary>
    public class EntityRef : IEntityRef {
        object _entity;
        ObjectIdT _id;

        public EntityRef(ObjectIdT id, object entity) {
            _id = id;
            _entity = entity;
        }

        public EntityRef(ObjectIdT id) {
            _id = id;
        }

        public ObjectIdT ObjectId {
            get { return _id; }
        }

        public object Entity {
            get { return _entity; }
            set { _entity = value; }
        }
    }

    /// <summary>
    /// Weak entity reference
    /// </summary>
    public class WeakEntityRef : WeakReference, IEntityRef {
        ObjectIdT _id;

        public WeakEntityRef(ObjectIdT id, object entity)
            : base(entity, false) {
            _id = id;
        }

        public ObjectIdT ObjectId {
            get { return _id; }
        }

        public object Entity {
            get {
                if (IsAlive)
                    return Target;
                return null;
            }

            set { Target = value; }
        }
    }
Re[34]: Объектные базы как они есть
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 19.04.05 18:27
Оценка:
Здравствуйте, GlebZ, Вы писали:

GZ>Здравствуйте, eao197, Вы писали:


GZ>Тут IMHO не все так однозначно. Изменение ссылки точно такая-же логгируемая операция, как и любое изменение объекта. То есть, при изменении, мы должны записать об этом в конце транзакции в лог. Попробуем рассмотреть оба варианта с точки зрения работы лога и транзакций.

GZ>В первом случае мы получаем, что при окончании транзакции мы сохраняем записи всем скопом в лог, и у нас при этом они кладуться в одну или несколько последовательных страниц.
GZ>Во втором случае, у нас в случае если транзакция read-only, мы вынуждены открыть ее (а я думаю лучше по соседству другую) как updatable. Но при этом, непонятна длительность этой транзакции, и количество данных которое должно быть сохранено существенно меньше чем размер страницы.

Я тоже думаю, что лучше другую. И сразу же ее зафиксировать.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re: Ссылки всякие нужны, ссылки всякие важны
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 19.04.05 18:27
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, eao197, Вы писали:


E>>Я когда-то делал два типа ссылок: soft_ref и hard_ref. Объясню на примерах. Пусть объект A ссылается на объект B с помощью seft_ref, а объект C ссылается на объект D с помощью hard_ref. Объекты B и D не могут быть удалены, пока существуют объекты A и C. Если же удаляется объект A, то объект B остается в базе, просто для него уменьшается счетчик ссылок. Если же удаляется объект C, то с ним вместе удаляется и объект D (при условии, что на него кроме A больше никто не ссылается). Т.е. hard_ref -- это отношение владения (D без С не может существовать), а soft_ref -- это соседские отношения.

S>Фактически, это третий тип ссылок. Трабл с ним я вижу в том, что не вполне понятно, что произойдет в случае наличия еще и soft_ref ссылок на объект D. Понятно, что само наличие двух hard_ref ссылок на один объект в такой системе — косяк. А вот что делать с софт ссылками — непонятно.

В моем случае наличие soft-ссылок на объект просто запрещало удаление объекта (т.е. связи были однонаправленными). Т.е., если в моем примере объект B имел soft-ссылку на объект D, то удаление C становилось невозможным (т.к. невозможно было удалить объект D).
... << RSDN@Home 1.1.4 beta 5 rev. 395>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[35]: Объектные базы как они есть
От: Alexey Rovdo Россия http://ru.linkedin.com/in/rovdo
Дата: 20.04.05 06:24
Оценка:
Здравствуйте, eao197, Вы писали:

GZ>>Тут IMHO не все так однозначно. Изменение ссылки точно такая-же логгируемая операция, как и любое изменение объекта. То есть, при изменении, мы должны записать об этом в конце транзакции в лог. Попробуем рассмотреть оба варианта с точки зрения работы лога и транзакций.

GZ>>В первом случае мы получаем, что при окончании транзакции мы сохраняем записи всем скопом в лог, и у нас при этом они кладуться в одну или несколько последовательных страниц.
GZ>>Во втором случае, у нас в случае если транзакция read-only, мы вынуждены открыть ее (а я думаю лучше по соседству другую) как updatable. Но при этом, непонятна длительность этой транзакции, и количество данных которое должно быть сохранено существенно меньше чем размер страницы.

E>Я тоже думаю, что лучше другую. И сразу же ее зафиксировать.


А надо ли это вообще оформлять как транзакцию (с логами и всем вытекающим)? Ведь в данном случае оба состояния (до и после) совершенно равнозначны и со стороны приложения не различимы.
Re[36]: Объектные базы как они есть
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 20.04.05 07:30
Оценка:
Здравствуйте, Alexey Rovdo, Вы писали:

AR>Здравствуйте, eao197, Вы писали:


GZ>>>Тут IMHO не все так однозначно. Изменение ссылки точно такая-же логгируемая операция, как и любое изменение объекта. То есть, при изменении, мы должны записать об этом в конце транзакции в лог. Попробуем рассмотреть оба варианта с точки зрения работы лога и транзакций.

GZ>>>В первом случае мы получаем, что при окончании транзакции мы сохраняем записи всем скопом в лог, и у нас при этом они кладуться в одну или несколько последовательных страниц.
GZ>>>Во втором случае, у нас в случае если транзакция read-only, мы вынуждены открыть ее (а я думаю лучше по соседству другую) как updatable. Но при этом, непонятна длительность этой транзакции, и количество данных которое должно быть сохранено существенно меньше чем размер страницы.

E>>Я тоже думаю, что лучше другую. И сразу же ее зафиксировать.


AR>А надо ли это вообще оформлять как транзакцию (с логами и всем вытекающим)? Ведь в данном случае оба состояния (до и после) совершенно равнозначны и со стороны приложения не различимы.


Имхо, любую модификацию БД нужно оформлять через транзакцию. Чтобы можно было восстановиться после сбоя. Ведь здесь речь идет не столько о логическом состоянии, которое видно для приложения, сколько о физической целостности страниц хранилища.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[37]: Объектные базы как они есть
От: Alexey Rovdo Россия http://ru.linkedin.com/in/rovdo
Дата: 20.04.05 07:51
Оценка:
Здравствуйте, eao197, Вы писали:

E>Имхо, любую модификацию БД нужно оформлять через транзакцию. Чтобы можно было восстановиться после сбоя. Ведь здесь речь идет не столько о логическом состоянии, которое видно для приложения, сколько о физической целостности страниц хранилища.


Так то оно так. Но может ли в обсуждаемом случае нарушиться физическая целостность? Смоделируйте ситуацию. Возможно здесь хватит и более простых мер?

Кстати, возвращаясь к упоминавшемуся мной ранее механизму версионности в FastObjects. Так вот там read-only операции не влияют на объект — он переформатируется в новую версию только тогда, когда приложение его редактирует.
Re[15]: Объектные базы как они есть
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 20.04.05 08:09
Оценка:
Здравствуйте, vdimas, Вы писали:

S>> Кстати разница в поиске не столь огромна для Б+ деревьев и хэш таблиц. На практике всего в 4 раза http://gzip.rsdn.ru/article/alg/tlsd.xml
Автор(ы): Сергей Смирнов (Serginio1)
Дата: 14.08.2004
Пример реализации двухуровневого массива с помощью нового средства С# — generics. Сравнение производительности различных реализаций сортированных списков.


V>Для моего "гибрида" я получал разницу в десятки раз. Это ощутимо и это причина пользовать именно ее.

V>На самом деле, если функция кеширования достаточно удачна (а я как разработчик практически всегда этого добиваюсь), то прирост быстродействия пропорционален двоичному логарифму размера хеш-таблицы. (по крайней мере, стремится к такой пропорциональности)

V>Далее, в подавляющем большинстве случаев у меня суррогатные ключи — это последовательность целых значений. Генератор ключей построен так, чот при удалении ключи не пропадают, а запоминаются в кеше и повторно применяются при следующих созданиях объектов. Т.е. при многократных удалениях/созданиях объектов у меня практически нет "дыр" в последовательности и мои хранилища являются иделальным вариантом для простейшей ф-ии кеширования X = key % cache_size.


Это все понятно и полностью согласен. Но есть одна вещь которая все эти предположения напрочь убивает, а именно кэш процессора, сброс кэша и доступ к медленной памяти. Кстати заметь, что в этом тесте моя хэш таблица в 1.8 раз быстрее нетовской. Но от коллизий ни куда не уйти и нужно нарываться на новый поиск, а данные могут находиться вне кэша.
Опять же для Б+ деревьев при определенном использовании верхнии уровни находятся в кэше процессора, поэтому поиск в них на больших данных оазывается быстрее, чем бинарный поиск в массиве с проинлайнниным компаратором, в отличие от компараторов Б+ (TLSD).
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
и солнце б утром не вставало, когда бы не было меня
Re[38]: Объектные базы как они есть
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 20.04.05 08:19
Оценка:
Здравствуйте, Alexey Rovdo, Вы писали:

AR>Здравствуйте, eao197, Вы писали:


E>>Имхо, любую модификацию БД нужно оформлять через транзакцию. Чтобы можно было восстановиться после сбоя. Ведь здесь речь идет не столько о логическом состоянии, которое видно для приложения, сколько о физической целостности страниц хранилища.


AR>Так то оно так. Но может ли в обсуждаемом случае нарушиться физическая целостность?


Легко. Мы же сейчас обсуждаем ситуацию, когда некий объект A ссылается на объект B посредством объекта связи C (A -> C -> B). При этом, после удаления или обнуления ссылки в B объект A продолжает ссылаться на C. При первом обращении к A нам нужно автоматически поднять объект C, увидеть, что он помечен как удаленный и сделать две вещи: удалить ссылку на C из A и удалить объект C.

Рассмотрим ситуацию с изменением A. Мы обнуляем в A один (или даже несколько) атрибутов. При последующей сериализации образ A может "поплыть", т.е. быть серьезно изменившимся по сравнению с исходным образом A. И дальше все зависит от того, как изменения укладываются в БД. Если A записывается на свое старое место, то может оказаться, что A размещался на нескольких страницах хранилища (вот такой он большой, например). Тогда сбой между записями страниц оставит БД в неверном состоянии. Если же новое значение A записывается в другое место хранилища с соответствующей корректировкой цепочки занятых блоков/страниц, то сбой между записью A и корректировкой блоков так же оставит БД в ошибочном состоянии. Аналогичные проблемы могут быть и при удалении объекта C из БД.

AR>Кстати, возвращаясь к упоминавшемуся мной ранее механизму версионности в FastObjects. Так вот там read-only операции не влияют на объект — он переформатируется в новую версию только тогда, когда приложение его редактирует.


А до этого в нашем случае СУБД будет вынуждена каждый раз тянуть за A объект C только для того, чтобы убедиться, что эта ссылка уже не действительна? А если объект A вообще больше никогда не будет извлекаться из БД для изменения, а только для чтения?
... << RSDN@Home 1.1.4 beta 5 rev. 395>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[39]: Объектные базы как они есть
От: Alexey Rovdo Россия http://ru.linkedin.com/in/rovdo
Дата: 20.04.05 08:48
Оценка:
Здравствуйте, eao197, Вы писали:

E>А до этого в нашем случае СУБД будет вынуждена каждый раз тянуть за A объект C только для того, чтобы убедиться, что эта ссылка уже не действительна? А если объект A вообще больше никогда не будет извлекаться из БД для изменения, а только для чтения?


А тогда и нужен GC, который сделае всю работу асинхронно в моменты слабой загрузки системы.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.