воскресенье, февраля 26, 2006

История изменения

Эта тема особенно беспокоит меня в последнее время. Что-то похожее уже было, но сейчас проблема предельно заострилась и формулируется так: требуется обобщённый механизм отката изменений в состоянии хранилищ на произвольное количество шагов. Важно, что в хранилище задаются неизвестные на момент создания механизма зависимости между объектами.

Предусловия.
1. Ничто не попадает в хранилище иначем, чем через адаптер.
2. Допустимо использование контекстов

Тогда.
Всю эту работу можно сделать довольно аккуратно при помощи атрибутов и контекстов.


[AttributeUsage(AttributeTargets.Class)]
public sealed class ReplicationTracingAttribute: ContextAttribute
{
public ReplicationTracingAttribute(): base("ReplicationTracing")
{
}
public override void GetPropertiesForNewContext(IConstructionCallMessage ctorMsg)
{
ctorMsg.ContextProperties.Add(new ReplicationTracingProperty());
}
}

при этом
ReplicationTracingProperty
выглядит так:

public class ReplicationTracingProperty: IContextProperty, IContributeObjectSink
{

Если теперь метод
GetObjectSink
интерфейса
IContributeObjectSink
определить так:
public IMessageSink GetObjectSink(MarshalByRefObject obj, IMessageSink nextSink)
{
return new ReplicationAspect(nextSink, obj);
}
то можно воспользоваться такой удобной вещью, как доступ к свойствам метода до того, как сам этот метод выполняется.

Смысл тут простой. На требуемые методы адаптеров навешиваются атрибуты отслеживания (см. выше), при вызове методов классов, реализующих адаптеры, поток выполнения заходит сначала в приёмник вызова. Этот самый приёмник что-то вроде пазухи, потайного кармана, расположенного между внутренней и наружной частью одежды. Если мы рассматриваем обычную модель работы со стеком, то между вызовом команды CALL процессора и снятием первого аргумента со стека в самой команде ничего нет. Вызвали - сняли со стека аргумент. А здесь, с приёмником, ситуация такая: закинули в стек аргументы, вызвали, а перед вызовом выполняется некий специальный код (это неинтересно объяснять, лучше один раз глянуть в MSDN), заворачивающий вызов метода в спец. оболочку, дающую доступ как к параметрам до вызова, так и к параметрам и возврату после вызова. Это чем-то похоже на генерирование защитного кода для тестирования обращения за пределы стека в Rational Purify, но гораздо более общо.

Ну так вот. Используя контексты вызова, можно протоколировать вызовы команд соответствующего сервера БД. В самом деле. В момент вызова уже известно, каким именно образом код будет сохранять (изменять, удалять данные) и всё, что потребуется - это просто посмотреть, кто именно вызывает методы изменения и с какими аргументами. Очень просто.

public IMessage SyncProcessMessage(IMessage Msg)
{
bool logOperation = Preprocess(Msg);
IMessage ret = m_NextSink.SyncProcessMessage(Msg);

if (logOperation)
PostProcess(Msg, ret);

return ret;
}

Не все операции надо протоколировать (например - можно протоколировать и SELECT, но зачем? Это задача аудита БД, мне нужно только протоколировать изменения и обеспечить откаты[в хорошем смысле]). Но если нужно протоколировать изменения, то метод PostProcess, вызываемый после собственно метода - то самое место, где будет выполняться запись протокола. В методе PostProcess для вызванного метода получаем перечень наших атрибутов, ну а дальше понятно. Единственное, что тут может потребоваться - это пояснить, как применяются и зачем тут атрибуты.

У меня они применяются так:

public interface IDataStorageAdapter
{
[AdapterReplication(SqlAction.Insert)]
long Insert(BaseItem Param);

[AdapterReplication(SqlAction.Update)]
int Update(BaseItem Param);

[AdapterReplication(SqlAction.Delete)]
int Delete(long Param);
...
}

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

Если рассматривать изменение хранилища, как последовательность вставок записей об изменениях, то процедура отката - очевидна. Однако, не всё так просто. Как правило, объекты сложны и сохраняются каскадами, а каждый каскад - внутри транзакции. В то время, как транзакции являются логическими единицами, вставки - являются единицами физическими, отследить по этим вставкам транзакции - не представляется возможным. Поэтому необходимо вводить маркеры, которые собой знаменовали бы начало транзакции. Я пишу это для того, чтобы лучше понять, каким образом должна быть написана спецификация на эту функциональность, не обманывай себя, о случайный читатель. Такими маркерами может быть вставка записи об объекте высокого уровня. Тогда разбиваем весь набор записей на классы по признаку уровень и выполняем откат от одной высокоуровневой записи до другой. Надо подумать, не является ли высокий уровень объекта достаточным условием для констатации отката транзакции полностью...

среда, февраля 22, 2006

Microsoft Battle Flight Simulator 3

Неделю назад наконец-то мне привезли из Америки эту игру. Авиасимуляторы я люблю, решил вот попробовать заморского... Что я могу сказать? Погань. Стоит в моём игровом 9600XT. Это, конечно, не сегодняшний день, но с Ил-2 нет ни малейших проблем. Всё на самом деле летает: быстрая анимация, натуральное сглаживание, тени, видимость, метеоусловия. А эта заморская херня? Сходное ощущение у меня было только однажды, когда я попытался на карте S3 Virge погонять в Carmageddon, году не то в 98м, не то в 99м.

Что тут можно ещё сказать? Я разочарован дважды. В первый раз тем, что вместо гражданских самолётов мне привезли симулятор боёв, во второй раз - убогостью исполнения. Что им нужно? X800? Почему Медоксу это не нужно?...

воскресенье, февраля 19, 2006

Ни о чём

Зашли поужинать в Тратторию. Заказы напоминали эпициклоиду. А последующая поездка домой - кардиоиду.

Некоторые кретины уверены, что слишком абстрактные или широкие определения свидетельствуют о шизофрении. Странно. Я всегда старался мыслить в абстрактных категориях, привлекая сущности лишь для иллюстрации и повышения доходчивости в случаях, когда это необходимо.

Вчера обнаружились первые признаки очередной бифуркации, а завтра будет известно, обманули признаки или нет.

Мне уже чего-то хочется написать. Надоело ковыряться в бумажках, которых единственное назначение есть только: дать всем понять, что мы не просто так ерундой занимаемся. Хочу запрограммировать придуманное. И как можно скорее.

вторник, февраля 14, 2006

Переделки

У нас начата миграция на .NET 2.0, удачно совпавшая с началом нового проекта. То есть, не то, чтобы он был совсем новым, но нужно так много сделать и столько переделать, что можно считать его новым.

Переделки начались "издаля". Сначала была подвергнута жестокой вивисекции рабочая библиотека, что уже пару лет помогает нам смотреть на объекты через призму ЕСС. Потом начали изменение кода самого приложения, чтобы технологическая сборка (как мы называем то, что делается для удостоверения в синтаксической корректности кода). Это заняло уже 5 дней и ещё займёт дня 3-4. Сегодня, говорят, удалось даже запустить этого гидроцефала и он пару минут работал :-). Хорошо, что есть люди, которые берутся за такую работу...

пятница, февраля 10, 2006

Прикладная нумерология

Только что в Sent Items упало письмо с порядковым номером 8888. Столько писем я отправил 12:20 25го мая 2002года. Теперь я знаю, как вечером развлекусь: закачаю в несчастную громоптицу все письма с 96года.

среда, февраля 08, 2006

Наборы разрешений

Странно, что до сих пор, хотя уже .NET 2.0 шагает по планете, есть масса людей,которые не знают, что такое PermissionSet, как они составляются, как задействуются, как выводятся из Evidences и при чём тут политики безопасности.

Возможно, это потому, что сделано не очень понятно. Я бы сделал проще. Вообще, ситуация мне напоминает год эдак 94й, когда все знали, что есть OLE2, но мало кто мог внятно изложить, что такое связывание, при чём там DDE и зачем нужны ConnectionPoints.

Материала по безопасности вокруг много, но не очень много я вижу связного. Не начать ли систематизировать и публиковать?...