Mikhail Sukhov
|
Date: 1/24/2011
|
|
|
|
aspirant Дело в том, что работа с плазовским стримом построена по принципу windows message loop: в неком методе программа вызывает метод CP2ConnectionClass.ProcessMessage(out cookie, PollInterval) в бесконечном цикле, а вся информация приходит через события. Если выводить создание и управление thread'ами, это нужно делать в отдельном классе. Иначе, если придется подключаться к стримам в нескольких местах, придется дублировать много кода.
Дубляж - это плохо. И плохо, когда стрим создает потоки (кол-во потоков не должно расти с количеством стримов). Плохо делать системный класс слишком уж умным. Код должен быть один и чтобы он управлял всеми стримами. aspirant Я помню о настраиваемости. Пока в черновом варианте я передаю путь к файлу, чтобы сразу можно было протестировать логику подключения, опроса, получения сообщений и т.д. С метаданными такая вещь: стримы в Плазе настраиваются из файлов, даже по умолчанию (методы TableSet.InitFromIni / TableSet.InitFromIni2). Если передавать классу PlazaStream в конструкторе PlazaTable, тогда внутри PlazaStream некий класс TableConfigParser должен будет генерить файл с нужной схемой, чтобы передать ее TableSet.InitFromIni. Здесь такой момент: предлагаю в SpecialFolder.ApplicationData создать путь Stocksharp\PlazaTrader\Scheme, в котором хранить свои конфиг-схемы-файлы или их создавать в папке TEMP. Создавать их в подпапке самой Плазы не стоит: требуется админский доступ.
В папке самого плаза шлюза вообще лучше ничего не править. По умолчанию лучше создавать пути в текущем каталоге (я думаю большинству этого будет достаточно). Плюс сделать путь настраиваемым. Вообщем, логика мне виделась такая (если такое невозможно, то поправьте):
- Создание PlazaTrader.
- Опционально. Модификация таблиц с метаданными.
- PlazaTrader.Connect.
- Проверка, есть ли ini файлы, соответствующие запрашиваемым метаданным.
- Если нет, то они создаются на основе PlazaTable.
- Есть, но с другими полями, то модифицируются.
- Подключение к Плазе и запуск вечного цикла.
aspirant Чтобы понимать в будущем, в каких случаях мы выкидываем PlazaException?
Только когда приходит плазовская ошибка (заявки, потоки или еще что). aspirant Насколько я понял, есть два варианта:
Одна особенность, все форматирование лучше помещать в PlazaFormatter. Потому как он уже используется для .NET -> Plaza при отправке транзакций. Не плохо было бы туда поместить и обратную трансформацию. aspirant На мой взгляд вызовы GetValAsХХХ(string fieldName) / GetValAsХХХByIndex(uint fieldIndex) нужно реализовать внутри PlazaStream, а мне чтобы дальше писать это класс нужно понимать: - PlazaStream - это служебный класс, или им смогут пользоваться клиенты (читай, сторонние разработчики, использующие PlazaTrader)?
- В каком виде выдавать данные классам, которые будут использовать PlazaStream? Через события по одной строчке с конвертацией CP2Record в массив object'ов? Или попробовать сделать что-то типа реализации интерфейса IDataReader с использованием CP2DataBufferClass?
1. Считаю, что нужно сделать внутренним, до тех пор, пока не попросят вынуть его наружу.[smile] 2. А нельзя просто выбрать данные в коллекцию и передавать уже ввиде родной .NET коллекции? aspirant И последнее насчет фильтрации данных в потоке. Есть предложение это тоже сделать внутри PlazaStream. Тогда при конвертации данных с помощью GetValAsХХХ() / GetValAsХХХByIndex() можно будет проверять только колонки, по которым идет фильтрация, и, если запись не подходит, не выдавать ее клиентскому коду.
Насчет оптимизации согласен, но опять получается ситуация со слишком умным PlazaStream.
|
|
Thanks:
|
|
|
|
|
Mikhail Sukhov
|
Date: 1/24/2011
aspirant Вчера разбирался со схемами таблиц потоков. Хочу выложить мои соображения:
Да, с точностью получился косяк. Надо исправлять. skuvv, вы все еще на метаданных? Тогда не пропустите момент, который указал aspirant.
|
|
Thanks:
|
|
|
|
|
skuvv
|
Date: 1/24/2011
Mikhail Sukhov aspirant Вчера разбирался со схемами таблиц потоков. Хочу выложить мои соображения:
Да, с точностью получился косяк. Надо исправлять. skuvv, вы все еще на метаданных? Тогда не пропустите момент, который указал aspirant. Добавил для всех сделанных мета-таблиц соответствующий PlazaType для decemical и string
|
|
Thanks:
|
|
|
|
|
aspirant
|
Date: 1/24/2011
|
|
|
|
Mikhail Sukhov Вообщем, логика мне виделась такая (если такое невозможно, то поправьте): - Создание PlazaTrader.
- Опционально. Модификация таблиц с метаданными.
- PlazaTrader.Connect.
- Проверка, есть ли ini файлы, соответствующие запрашиваемым метаданным.
- Если нет, то они создаются на основе PlazaTable.
- Есть, но с другими полями, то модифицируются.
- Подключение к Плазе и запуск вечного цикла.
Этап 2 (опционально): создание таблиц PlazaTable кодом клиента (либо нужный набор колонок, либо все) + наш код парсит все ini файлов в заданной директории для создании на их основе таблиц PlazaTable (через метод PlazaTableSerializer.Deserialize(string fileName) + отслеживаем изменения/добавления файлов в этой директории. Здесь, кстати, уточнение: в предыдущем посте я был не прав. вот, что написано в документации (P2ClientGate.doc стр. 18): "Клиент также может не указывать никакой схемы при открытии потока, в этом случае сервер будет отдавать все данные, которые публикуются в потоке (далее этот режим будет называться «получение данных по схеме сервера»)." Т.е., если в потоке несколько таблиц, будут выдаваться данные по всем таблицам. Для управления стримами (PlazaStream) я создам PlazaStreamManager, который будет внутри себя создавать стримы, подписываться на их события и управлять их подключением / отключением (т.е. внутри него будет бесконечный цикл). В PlazaStreamManager код пользователя передает коллекцию таблиц (по одной или сразу IEnumerable<PlazaTable>) из предыдущего пункта. Этап 3 (PlazaTrader.Connect): если в PlazaStreamManager есть стримы, запускаем его. Все стримы будут вертеться в одном потоке (thread). Как дополнительную опцию (третьестепенная / четвертостепенная задача), добавить возможность создания приоритетных стримов в отдельном потоке (thread). Не знаю, нужно ли это? Mikhail Sukhov 2. А нельзя просто выбрать данные в коллекцию и передавать уже ввиде родной .NET коллекции?
Насколько я понял, принцип работы со стримами в Плазе следующий: создаем и инициализируем CP2DataStream, затем CP2TableSet (у каждого стрима только один CP2TableSet). Далее подписываемся на события, открываем стрим. После "рукопожатия" (StreamLifeNumChanged) приходит событие StreamDataBegin - данные пошли. Они идут через StreamDataInserted по одной строке. Когда некий объем данных заканчивается, приходит StreamDataEnd. Мне интересно, как часто Plaza выдает событие StreamDataEnd. Хочу в ближайшие пару дней запустить какую-нибудь тестовую программу на пару часов и посмотреть. Если прерывания случаются часто, то действительно можно копить строки (записи) в PlazaStreamManager и выдавать клиенту, например, DataTable или DataRow[] и т.д. Вместе с этим, мне кажется, нужно дать возможность клиенту тоже получать наш вариант StreamDataInserted, тем более что кроме него там еще есть StreamDataUpdated и StreamDataDeleted. В этих событиях можно через PlazaFormatter конвертировать данные в .Net'овские, помещать их в List<object> и выдавать последний клиенту, как object[]. Последнее, насчет фильтрации. Можно будет предусмотреть некий интерфейс IPlazaFilter с методом bool Validate(CP2Record rec, + что-нибудь еще). В методе PlazaStreamManager, который создает новый стрим, можно передавать IEnumerable<IPlazaFilter> или null, который будет привязываться к конкретному стриму. Тогда PlazaStreamManager будет перебирать для каждого стрима его IEnumerable<IPlazaFilter> в событиях StreamDataInserted / StreamDataUpdated / StreamDataDeleted, и если какой-то IPlazaFilter возвращает false, не выдавать событие с данными клиенту.
|
|
Thanks:
|
|
|
|
|
aspirant
|
Date: 1/24/2011
skuvv Mikhail Sukhov aspirant Вчера разбирался со схемами таблиц потоков. Хочу выложить мои соображения:
Да, с точностью получился косяк. Надо исправлять. skuvv, вы все еще на метаданных? Тогда не пропустите момент, который указал aspirant. Добавил для всех сделанных мета-таблиц соответствующий PlazaType для decemical и string Круто[biggrin]. Я только собрался писать об этом изменении. Даже сам еще свои таблицы не исправил.
|
|
Thanks:
|
|
|
|
|
aspirant
|
Date: 1/29/2011
|
|
|
|
Только что залил изменения. Хотел поделиться промежуточными итогами: - В класс PlazaColumns добавил три поля:
ReplicationStream ReplicationStream { get; } string Table { get; } ReplicationScheme ReplicationScheme { get; } Пока сделал их все virtual, чтобы код компилировался, но вообще первые два поля должны быть abstract, чтобы все классы-наследники их переписали для себя. Правильные объявления я пока закомментил. Эти три поля часть метаданных (у каждого наследника PlazaColumns может быть только один набор значений ReplicationStream - ReplicationScheme - Table) и нужны для инициализации PlazaTable, чтобы потом можно его было передать в PlazaStream или просто сохранить на диск через PlazaTableSerializer.
- Написал первый вариант PlazaStreamManager: пока только создает / удаляет объекты PlazaStream и перехватывает их события. Весь "ум" из класса PlazaStream убрал. Теперь это по сути обертка для CP2DataStreamClass. Его нужно будет протестировать со всеми наследниками наследника PlazaColumns на предмет правильности описания метаданных. Я его тестировал с PlazaRtsIndexColumns и еще парой классов. Кстати, при запуске метода Start() PlazaStreamManager начинает заметно подтормаживать GUI-поток .Net'овскго тестового проекта.
- Получение данных пока только получалось тестировать после работы: приходит сразу некая порция строк плазовского потока репликации и все. Днем один раз получилось запустить PlazaStream + PlazaRtsIndexColumns: данные сыпались непрерывно где-то минут пять точно, потом мне нужно было идти.
Хотелось получить ваши комментарии, рекомендации и т.д., после чего продолжу работу на PlazaStreamManager. Там еще полно дел. Кроме того еще нужно дописать PlazaTableSerializer.
|
|
Thanks:
|
|
|
|
|
aspirant
|
Date: 1/29/2011
Кстати, только что заметил, что мой PlazaRtsIndexColumns дублируется с PlazaIndexColumns. Сейчас удалю свое детище[sad]
|
|
Thanks:
|
|
|
|
|
skuvv
|
Date: 1/30/2011
Добавил класс с кодами ошибок плазы - PlazaErrors парсит код ошибки и возвращает текст ps ктото начал заниматься ошибками - пользуйтесь
|
|
Thanks:
|
|
|
|
|
Mikhail Sukhov
|
Date: 1/30/2011
aspirant Кстати, только что заметил, что мой PlazaRtsIndexColumns дублируется с PlazaIndexColumns. Сейчас удалю свое детище[sad] А csproj до сих пор на него ссылается. Коммитить нужно все атомарно.
|
|
Thanks:
|
|
|
|
|
Mikhail Sukhov
|
Date: 1/30/2011
|
|
|
|
aspirant Хотелось получить ваши комментарии, рекомендации и т.д., после чего продолжу работу на PlazaStreamManager. Там еще полно дел. Кроме того еще нужно дописать PlazaTableSerializer.
1. Плохой код. Codetry { _dataStream.Close(); } catch (System.Runtime.InteropServices.COMException e) { // Исправить обработку исключения System.Diagnostics.Trace.WriteLine("Exception {0:X}: {1}".Put(e.ErrorCode, e.Message)); } Исключения нужно перехватывать как можно выше. Кто будет вызывать Close, тот пусть и этим занимается. А так ошибка просто проглотиться. 3. Code_dataStream.TableSet.set_rev(plazaTable.Name, _currentRevision++); Это меняется на более элегантное, как подсказал R#: Code_dataStream.TableSet.rev[plazaTable.Name] = _currentRevision++; 4. ReplicationStream и ReplicationScheme явно как то не так используется. Это же уровень метаданных, а именно таблица PlazaTable (таблица олицетворяет стрим данных, PlazaStream по этом олицетворению производит подключение). А получилось так, что эти два перечисления размазались по всем практически классам в Плазе. Нехорошо. Конструктора PlazaStream(PlazaTable plazaTable, TRequestType requestType) более чем достаточно. Зачем нужен еще один я не понял. 5. public void AddStream(string key, PlazaColumns schema, IEnumerable<PlazaColumn> columns) Выглядит как то не так. Зачем столько аргументов? Можно же ведь передать один PlazaTable и уже по нему создать стрим, и уже оперировать им в дальнейшем.
|
|
Thanks:
|
|
|
|