Автор Тема: Горячая замена кода  (Прочитано 23412 раз)

ilovb

  • Hero Member
  • *****
  • Сообщений: 2538
  • just another nazi test
    • Просмотр профиля
    • Oberon systems
Горячая замена кода
« : Декабрь 04, 2013, 09:17:18 am »
В конфе в очередной раз зашел разговор за горячую замену кода в ББ. У народа оказывается с этим есть проблемы. И более того говорят что ее там нет!

Сначала было непонятно, что собственно хотят изобразить. Теперь же есть пример проблемного кода:

MODULE A;
IMPORT StdLog;
 
TYPE
T0* = EXTENSIBLE RECORD END;
PT* = POINTER TO T0;
 
VAR
r* : PT;

PROCEDURE (ob : PT) Some*(), NEW, EXTENSIBLE;
BEGIN
StdLog.Int(42);
END Some;

PROCEDURE Test*(); BEGIN
r.Some()
END Test;
 
BEGIN
END A.
 
MODULE B;
IMPORT A, StdLog;
 
TYPE
T1* = RECORD (A.T0) END;
PT* = POINTER TO T1;
VAR
r : PT;

PROCEDURE (ob : PT) Some*();
BEGIN
StdLog.Int(13)
END Some;
 
PROCEDURE Test*();
BEGIN
NEW(r);
A.r := r;
A.Test();
END Test;

END B.
 
(!) B.Test
Unload B
(!) A.Test
Trap
https://gist.github.com/valexey/7777367

Вах! Вот ведь неразрешимый трабл! Если модуль-владелец отдает свой объект в другой модуль, то ББ не отслеживает при вызове методов, что модуль-владелец может быть выгружен. То что мы в данном случае получаем штатный трап народ не впечатлило. Тот факт, что эта ошибка уровня разыменования NIL (что как бэ намекает) никого тоже не колышит:
Цитировать
[01:44:23] <vlad2> boris_ilov: это хреновый трап и принципиально не такой как в случа NIL
Хотя лично я разницы не вижу (и ББ тоже не видит, в чем легко убедиться заглянув в исходники)

Теперь по обсуждаемому коду.
Совершенно очевидно, что этот код не будет работать. Что автор хотел получить от ББ для меня загадка. ББ не подгружает модуль если его прямо или косвенно не импортировать. Неявный импорт средой не отслеживается очевидно по соображениям производительности. НО! Даже если бы ББ это делал, то это не помогло бы автору. Ибо проблема рук и лени средствами среды не лечится.
Если автор хотел горячую замену реализации в реальном времени, то очевидно, что это делается не так. И это известно любому, кто читал документацию.
Уже неоднократно говорилось о паттерне Dir (который собсна и описан в доке). Народ упрямо игнорит сию информацию.
Горячая замена с паттерном Dir делается элементарно и безопасно.

Почему-то я делал такое ни один раз и никаких AV не получал. Более того я даже не знал что ББ не отслеживает выгрузку модуля. И все потому, что мне в голову не приходило изобразить такой код. Паттерн Dir - это первое, что я вспомню если мне нужно подменить реализацию в реальном времени.

Так в чем же проблема? В ББ? Или в нежелании использовать ООП, в ООП-языке?

Geniepro

  • Hero Member
  • *****
  • Сообщений: 1955
  • Знайте- истина в том, что повторено трижды подряд!
    • Просмотр профиля
Re: Горячая замена кода
« Ответ #1 : Декабрь 04, 2013, 09:44:39 am »
Горячая замена с паттерном Dir делается элементарно и безопасно.

Почему-то я делал такое ни один раз и никаких AV не получал. Более того я даже не знал что ББ не отслеживает выгрузку модуля. И все потому, что мне в голову не приходило изобразить такой код. Паттерн Dir - это первое, что я вспомню если мне нужно подменить реализацию в реальном времени.

А как будет это выглядеть с использованием паттерна Dir?
to iterate is human, to recurse, divine

Салат «рекурсия»: помидоры, огурцы, салат…

ilovb

  • Hero Member
  • *****
  • Сообщений: 2538
  • just another nazi test
    • Просмотр профиля
    • Oberon systems
Re: Горячая замена кода
« Ответ #2 : Декабрь 04, 2013, 09:54:13 am »
Чтобы приготовить горячую замену в реальном времени нужно:
0. Уяснить, что замена реализации - это подмена объекта. (если у нас куча объектов, то это элементарно решается композицией, т.е. объекты ссылаются на один объект-реализацию)
1. Экспортная (для чтения) переменная Dir - текущая реализация
2. Экспортная (для чтения) переменная StdDir - Реализация по дефолту от модуля-владельца Dir
3. Метод установки объекта в Dir (с проверкой на NIL)

Во время работы программы можно подменять Dir хоть до посинения. И мы всегда можем вернуться к дефолтной реализации.

Все.

Если мы вдруг желаем заменять реализацию в процессе разработки (перекомпилируем и выгружаем модули), то достаточно в секции CLOSE добавить вызов метода SetDir(StdDir).

ilovb

  • Hero Member
  • *****
  • Сообщений: 2538
  • just another nazi test
    • Просмотр профиля
    • Oberon systems
Re: Горячая замена кода
« Ответ #3 : Декабрь 04, 2013, 10:05:27 am »
На самом деле Dir - это про фабрики, но у нас тут немного другая задача.

Wlad

  • Jr. Member
  • **
  • Сообщений: 91
    • Просмотр профиля
Re: Горячая замена кода
« Ответ #4 : Декабрь 04, 2013, 02:29:14 pm »
В конфе в очередной раз зашел разговор за горячую замену кода в ББ. У народа оказывается с этим есть проблемы. И более того говорят что ее там нет!
Свои пять копеек.
Мне интересно, а как вообще можно (в "архитектурном смысле") уничтожать объект, который служит оболочкой для ссылаемой сущности/переменной???
Модуль, кроме чисто синтаксической роли объединения чего-то "в одну кучку", ещё ведь является неким "объектом"-синглтоном. Или я не прав?

vlad

  • Hero Member
  • *****
  • Сообщений: 1391
    • Просмотр профиля
Re: Горячая замена кода
« Ответ #5 : Декабрь 04, 2013, 04:13:55 pm »
То что мы в данном случае получаем штатный трап народ не впечатлило. Тот факт, что эта ошибка уровня разыменования NIL (что как бэ намекает) никого тоже не колышит:
Цитировать
[01:44:23] <vlad2> boris_ilov: это хреновый трап и принципиально не такой как в случа NIL
Хотя лично я разницы не вижу (и ББ тоже не видит, в чем легко убедиться заглянув в исходники)

Поясняю: трап хреновый потому что он ровно из той же серии, что и разыменование невалидного (dangled) указателя в C/C++. Только в случае С/C++ никто не кричит, что такой трап штатный, а идут и фиксают :) Хотя, например, C++Builder из коробки такие трапы ловит не хуже ББ и ничего не падает (наследнику дельфи, чего с него взять).

Последствия/уязвимости у таких трапов, соответственно, точно такие же как и у традиционных небезопасных языков (форматирование жесткого диска и т.д. и т.п.).

vlad

  • Hero Member
  • *****
  • Сообщений: 1391
    • Просмотр профиля
Re: Горячая замена кода
« Ответ #6 : Декабрь 04, 2013, 04:18:01 pm »
Мне интересно, а как вообще можно (в "архитектурном смысле") уничтожать объект, который служит оболочкой для ссылаемой сущности/переменной???
Модуль, кроме чисто синтаксической роли объединения чего-то "в одну кучку", ещё ведь является неким "объектом"-синглтоном. Или я не прав?

Все правильно. Естественно, что при насильной выгрузке/замене будут определенные конфликты. Началось все с того, что Алексей будучи под впечатлением от того как хорошо продуманы эти моменты в эрланге сказал, что в ББ оно вообще никакое. Вот и все.

Geniepro

  • Hero Member
  • *****
  • Сообщений: 1955
  • Знайте- истина в том, что повторено трижды подряд!
    • Просмотр профиля
Re: Горячая замена кода
« Ответ #7 : Декабрь 04, 2013, 04:23:03 pm »
В конфе в очередной раз зашел разговор за горячую замену кода в ББ. У народа оказывается с этим есть проблемы. И более того говорят что ее там нет!

Свои пять копеек.
Мне интересно, а как вообще можно (в "архитектурном смысле") уничтожать объект, который служит оболочкой для ссылаемой сущности/переменной???
Модуль, кроме чисто синтаксической роли объединения чего-то "в одну кучку", ещё ведь является неким "объектом"-синглтоном. Или я не прав?

Ну, скажем, в Ерланге сделано примерно так:

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

Если же изменения были достаточно серьёзными и привели к нарушению целостности данных (например, из-за изменения структур данных в этом модуле), то придётся останавливать софт и выгружать старые версии модулей вручную -- как в оберонах...
to iterate is human, to recurse, divine

Салат «рекурсия»: помидоры, огурцы, салат…

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
Re: Горячая замена кода
« Ответ #8 : Декабрь 04, 2013, 04:24:57 pm »
Поясню свою мысль - в ББ есть закгрузка и выгрузка модулей. Но горячей замены кода там нет.

Её там можно сделать для некоторых (своих) специально спроектированных модулей.

(аналогия - Точно также можно сделать сборку мусора для некоторых (своих) классов в С++. Но от этого в С++ сборщик мусора внезапно не появляется)

Вот и всё.
Y = λf.(λx.f (x x)) (λx.f (x x))

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
Re: Горячая замена кода
« Ответ #9 : Декабрь 04, 2013, 04:30:13 pm »
Если же изменения были достаточно серьёзными и привели к нарушению целостности данных (например, из-за изменения структур данных в этом модуле), то придётся останавливать софт и выгружать старые версии модулей вручную -- как в оберонах...

Это не так :-) Для этого там есть OTP. Грубо говоря, при замене кода тебе прилетает событие и ты можешь сконвертировать все данные в новый формат. Вообще же в ББ просто инкапсуляция недостаточна для полноценной замены кода. Поясню - нужена не общая свалка в памяти, где объекты (и ссылки на них) гуляют как хотят и модифицируются как хотят, а нужно множество отдельных кучек, где за каждую кучку ответственен вполне конкретный кусок кода, множество процессов которые взаимодействуют через сообщения (полноценные, а не те которые в "messge bus" в ББ). Вот тогда появляется шанс сделать правильную горячую замену кода в общем случае.

Как, по моему, Зефиров говорил - в erlang'e есть искаробки какая-то горячая замена кода, в других системах её можно делать ручками (и ББ не исключение, да), в erlang'e можно сделать правильную горячую замену кода, в других системах её просто не сделать.
Y = λf.(λx.f (x x)) (λx.f (x x))

vlad

  • Hero Member
  • *****
  • Сообщений: 1391
    • Просмотр профиля
Re: Горячая замена кода
« Ответ #10 : Декабрь 04, 2013, 04:34:39 pm »
Чтобы приготовить горячую замену в реальном времени нужно:

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

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

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

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
Re: Горячая замена кода
« Ответ #11 : Декабрь 04, 2013, 04:41:55 pm »
Или на таймер (50 раз в секунду) повесили коллбэк, который ведет в выгружаемый модуль. Ну и тому подобное.
Ну вот у меня как раз, тот самый штатный нормальный трап при неосторожной выгрузке модуля (чтобы заменить более свежей версией) генерился со скоростью 30 раз в секунду :-) Правда весело? ;-)

Один Compile&Unload и ББ встал колом - все зарасло окошками с трапами.

Причем ничего военного я не делал - просто встраиваемую кастомную вьюшку (показывало изображение с камеры в реальном времени). Вот так работает каркас.
Y = λf.(λx.f (x x)) (λx.f (x x))

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
Re: Горячая замена кода
« Ответ #12 : Декабрь 04, 2013, 04:44:39 pm »
Y = λf.(λx.f (x x)) (λx.f (x x))

ilovb

  • Hero Member
  • *****
  • Сообщений: 2538
  • just another nazi test
    • Просмотр профиля
    • Oberon systems
Re: Горячая замена кода
« Ответ #13 : Декабрь 04, 2013, 04:46:23 pm »
Последствия/уязвимости у таких трапов, соответственно, точно такие же как и у традиционных небезопасных языков (форматирование жесткого диска и т.д. и т.п.).

Какие еще уязвимости? O_o

vlad

  • Hero Member
  • *****
  • Сообщений: 1391
    • Просмотр профиля
Re: Горячая замена кода
« Ответ #14 : Декабрь 04, 2013, 04:47:15 pm »
Вот так работает каркас.

Ну это просто обратная сторона (нерекламируемая :) подхода "программа и IDE как единое целое". Насильная выгрузка модулей тут просто добавляет чуток энтропии :)