Автор | Сообщение |
Pasha
|
| Администратор
|
Пост N: 1937
Зарегистрирован: 23.05.05
|
|
Отправлено: 18.05.11 19:04. Заголовок: Leto DB Server
Добавил функцию: LETO_GROUPBY(cGroup, cFields, [cFilter], [xScopeTop], [xScopeBottom]) cGroup - имя поля, по которому группируются данные; cFields - список числовых полей через запятую, которые суммируются. Символ # обозначает к-во записей в группе Функция возвращает двумерный массив строк. 1-й элемент каждой строки - значение поля cGroup, следующие элементы суммы полей, заданных в cFields, или к-во записей в группе
|
|
|
Ответов - 232
, стр:
1
2
3
4
5
6
7
8
9
10
11
12
All
[только новые]
|
|
AlexMyr
|
| |
Пост N: 188
Зарегистрирован: 11.06.10
|
|
Отправлено: 31.05.11 13:53. Заголовок: alx_on пишет: AlexM..
alx_on пишет: цитата: | AlexMyr Странно... Перевыложил |
| Теперь нормально собралось.
|
|
|
AlexMyr
|
| |
Пост N: 189
Зарегистрирован: 11.06.10
|
|
Отправлено: 31.05.11 14:00. Заголовок: Останавливаю сервер,..
Останавливаю сервер, в логе запись 05/31/11 13:57:23: Send STOP to server... может быть так 05/31/11 13:57:23: Send STOP to server... Done. а то послали stop а результата в логе нет.
|
|
|
AlexMyr
|
| |
Пост N: 190
Зарегистрирован: 11.06.10
|
|
Отправлено: 31.05.11 14:10. Заголовок: О, увидел, оказывает..
О, увидел, оказывается задержка есть 3 сек. 05/31/11 14:08:22: Send STOP to server... 05/31/11 14:08:25: Server has been closed.
|
|
|
alx_on
|
| постоянный участник
|
Пост N: 113
Зарегистрирован: 07.07.09
|
|
Отправлено: 31.05.11 15:47. Заголовок: Pasha пишет: Версия..
Pasha пишет: цитата: | Версия с потоками куда перспективнее, и она просто должна стать основной |
| Я считаю, что текущая реализация хороша, но до определенных пределов Какие есть недостатки: 1. Запуск отдельного потока для каждого подключения накладно. Как по времени запуска, так и по ресурсам. На машинке (win) с 2Гб у меня запустилось около 800 потоков (вроде много, но если клиентов около 100 и каждый создал по 10 соединений, например, это многопоточное клиентское приложение, то к пределу мы уже подошли) 2. Неэффективное использование ядер (больше времени уходит на переключение между ядрами, чем на работу Хочется переделать на использование ограниченного кол-ва рабочих потоков (в идеале, примерно, равное кол-ву ядер) Плюс оптимизация сетевой подсистемы (с учетом реализации стека TCP/IP конкретной ОС) Но! То что поточная реализация точно лучше старой - это факт.
|
|
|
alx_on
|
| постоянный участник
|
Пост N: 114
Зарегистрирован: 07.07.09
|
|
Отправлено: 01.06.11 13:16. Заголовок: Pasha пишет: надо д..
Pasha пишет: цитата: | надо добавить функцию leto_areaid() |
| Я (пока?) не использую UDF Поэтому добавить то могу, но тестировать не на чем. Да и времени сейчас на это нет, честно говоря. Исправляю и добавляю только по мере необходимости, как это не грустно PS leto_ClearAreaEnv() вызывается каждый раз перед завершением операции Так ли это необходимо? Вызова leto_SetAreaEnv() перед операцией вполне достаточно Какие есть мнения?
|
|
|
Pasha
|
| Администратор
|
Пост N: 1960
Зарегистрирован: 23.05.05
|
|
Отправлено: 01.06.11 14:32. Заголовок: Да функцию я и сам д..
Да функцию я и сам добавлю А leto_ClearAreaEnv() для версии с двумя потоками был просто необходим, так как рабочая область таблицы для всех пользователей была общая, и ее обязательно надо было сбрасывать Для mt-версии наверное это и не надо.
|
|
|
Pasha
|
| Администратор
|
Пост N: 1962
Зарегистрирован: 23.05.05
|
|
Отправлено: 02.06.11 09:56. Заголовок: Странно, функция let..
Странно, функция leto_areaid() и не понадобилась Сделал udf-функцию для каскадного обновления (вечером выложу): /* * UDF_UpdCascade - cascade update key fields in main and relation table * Parameters: * nRecNo - record number in the main table * cKeyField - field name in the main table (primary key) * xKeyNew - new value of key field * cClientAlias - client alias of the relation table * cKeyField2 - field name in the relation table (foreign key) * xOrder - order name or order number in the relation table * * This function return array of record buffer in two tables * Call from client: * * aRecBuf := Leto_Udf("UDF_UpdCascade", ... ) * (table1)->( leto_ParseRec( aRecBuf[1] ) ) * (table2)->( leto_ParseRec( aRecBuf[2] ) ) */ FUNCTION UDF_UpdCascade( nUserStru, nRecNo, cKeyField, xKeyNew, cClientAlias, cKeyField2, xOrder ) LOCAL xKeyOld, cLetoAlias, cArea := Alias() LOCAL nPos := FieldPos( cKeyField ), nPos2 dbGoto( nRecNo ) xKeyOld := FieldGet( nPos ) IF xKeyOld != xKeyNew .and. leto_RecLock( nUserStru, nRecNo ) FieldPut( nPos, xKeyNew ) leto_RecUnlock( nUserStru, nRecNo ) cLetoAlias := leto_Alias( nUserStru, cClientAlias ) dbSelectArea( cLetoAlias ) IF Empty( cKeyField2 ) cKeyField2 := cKeyField ENDIF nPos2 := FieldPos( cKeyField2 ) IF ! Empty( xOrder ) ordSetFocus( xOrder ) ENDIF WHILE dbSeek( xKeyOld ) IF leto_RecLock( nUserStru, RecNo() ) FieldPut( nPos2, xKeyNew ) leto_RecUnlock( nUserStru, RecNo() ) ELSE EXIT ENDIF ENDDO dbSeek( xKeyNew ) dbSelectArea( cArea ) ENDIF RETURN { leto_rec( nUserStru ), (cLetoAlias)->(leto_rec( nUserStru)) } И оказалось, что при выборе текущей раб.области pUStru->pCurAStru сам присваивается, только мне непонятно как
|
|
|
alx_on
|
| постоянный участник
|
Пост N: 115
Зарегистрирован: 07.07.09
|
|
Отправлено: 02.06.11 10:32. Заголовок: Pasha пишет: pUStru..
Pasha пишет: цитата: | pUStru->pCurAStru сам присваивается, только мне непонятно как |
| leto_Alias() - вызывает leto_SelectArea(), там все делается цитата: | IF ! Empty( xOrder ) ordSetFocus( xOrder ) ENDIF WHILE dbSeek( xKeyOld ) |
| Вот здесь я был бы осторожнее, т.к. не факт, что от другого UDF не остались установленные фильтры и скопы Лучше все сбрасывать перед операциями поиска и прохода по записям Кстати, недостатки текущей реализации UDF: 1 неудобно каждый раз вручную обновлять файл UDF на сервере 2 требуется рестарт сервера 3 непонятно какая именно версия UDF на сервере Как такая идея работы с UDF: 1. Написать функцию отдачи версии UDF-файла (или каждая UDF-функция должна уметь вернуть свою версию) 2. Написать функцию обновления версии UDF-файла (соответственно сервер должен уметь перечитать его) 3. удаление UDF-файла
|
|
|
Pasha
|
| Администратор
|
Пост N: 1963
Зарегистрирован: 23.05.05
|
|
Отправлено: 02.06.11 11:09. Заголовок: По поводу areaid - н..
По поводу areaid - не все так просто. leto_rec использует текущий алиас - pArea, и текущую pUStru->pCurAStru. А они в UDF_UpdCascade оказываются разные: AREASTRU для обоих вызовов одинаковая. Так что запрос areaid и ее установка через leto_selectarea() все-таки нужна. Может лучше передавать ее параметром (необязательным) в leto_rec, leto_reclock, leto_recunlock ? Насчет фильтров - ведь каждая udf-функция вызывается по отдельному запросу с клиента, и после ее работы отрабатывается FreeArea, которая должна все сбросить. Это получается как для leto_ClearAreaEnv(). Установленный фильтр надо проверять разве что если одна UDF-функция вызывается из другой. Reload/Unload для UDF сделаю, по аналогии с отработки команды stop - LETO_STOPSERVER. Там надо вызывать hb_hrbunload/hb_hrbload По поводу версии UDF. Может в hrb-модуль добавить функцию UDF_Version, которая возвращала бы строку версии, и с клиента ее можно опросить обычным вызовом leto_Udf('UDF_Version') ? Кстати, можно еще определить функию UDF_INIT, которую сервер вызывал бы при загрузке UDF (если она есть в модуле, конечно)
|
|
|
Pasha
|
| Администратор
|
Пост N: 1964
Зарегистрирован: 23.05.05
|
|
Отправлено: 02.06.11 11:14. Заголовок: alx_on пишет: 2. На..
alx_on пишет: цитата: | 2. Написать функцию обновления версии UDF-файла (соответственно сервер должен уметь перечитать его) |
| А, это запросом с клиента обновлять UDF ? Можно и так, добавить команду, и с ней передавать hrb-файл, который сервер бы загружал
|
|
|
alx_on
|
| постоянный участник
|
Пост N: 116
Зарегистрирован: 07.07.09
|
|
Отправлено: 02.06.11 11:39. Заголовок: Pasha пишет: leto_r..
Pasha пишет: цитата: | leto_rec использует текущий алиас - pArea, и текущую pUStru->pCurAStru. |
| Вот именно. Т.е. использование UDF требует аккуратности (мало ли где еще неявно что то используется) Например можно вместо: dbSelectArea( cArea ) ENDIF RETURN { leto_rec( nUserStru ), (cLetoAlias)->(leto_rec( nUserStru)) } написать так: LOCAL aRet := {,} ....... ....... aRet[2] := leto_rec( nUserStru ) dbSelectArea( cArea ) aRet[1] := leto_rec( nUserStru ) ENDIF RETURN aRet Плюс правильно отработать условие "IF xKeyOld != xKeyNew .and. leto_RecLock( nUserStru, nRecNo )" - (пустой массив) Сейчас просто будет падать (cLetoAlias == NIL) цитата: | после ее работы отрабатывается FreeArea, которая должна все сбросить. Это получается как для leto_ClearAreaEnv() |
| leto_FreeArea() не сбрасывает ничего (явно, по крайней мере), она только передает таблицу в общее пользование потокам цитата: | Может в hrb-модуль добавить функцию UDF_Version |
| Как вариант, да согласен
|
|
|
|
Pasha
|
| Администратор
|
Пост N: 1970
Зарегистрирован: 23.05.05
|
|
Отправлено: 08.06.11 21:23. Заголовок: Обновление обьекта t..
Обновление обьекта tbrowse происходит так: go top перемещение в начало, вывод строки skip 1 вывод строки skip 1 ... skip -n возврат на первую строку Применительно к letodb это будет выглядеть так: go top выборка записи с сервера skip 1 n записей со 2-й выбираются с сеовера skip 1 запись берется из буфера без обращения к серверу ... skip -n записи с n до 2 беоутся из буфера, а 1-я вновь запрашивается с сервера Чтобы избежать лишнего запроса, я сделал буферизацию записи, которая получена при gotop/gobottom/goto/seek Таким образом, теперь при стабилизации tbrowse к letodb клиент посылает всего 2 запроса: gotop skip Конечно, при этом буфер для skip должен быть не меньше, чем количество строк в tbrowse Для этого можно вызвать: leto_SetSkipBuffer( oB:rowCount() ) Заодно добавил оптимизацию dbGoto: если запрашиваемая запись есть в буфере, она не считывается с сервера.
|
|
|
Pasha
|
| Администратор
|
Пост N: 1971
Зарегистрирован: 23.05.05
|
|
Отправлено: 10.06.11 16:15. Заголовок: Помимо буферизации s..
Помимо буферизации skip хочется добавить в letodb буферизацию seek. Предполагается делать буферизацию исключительно на клиенте, сервер при этом задействован не будет. После выполнения seek, если это не поиск по частичному ключу и не поиск последнего ключа, результат поиска добавляется в буфер. Время актуальности буфера - BUFF_REFRESH_TIME (1 сек) Если ключ для seek найден в буфере, то запрос к серверу не выполняется, а запись берется из буфера. Буфер хранится в LETOTAGINFO. При записи в таблице буфер очищается. Использование seek buffer будет целесообразно для небольших справочников, для которых постоянно вызывается seek, а также при задании set relation. Для р/о, в которой задано использование seek buffer, количество мелких запросов к серверу (seek) может быть сокращено в десятки раз. В Ads, насколько я знаю, подобного механизма нет. Какие будут мысли, идеи, сомнения ? Стоит ли использовать такой механизм по умолчанию для всех р/о, или только для заданных ? Как ограничивать размер такого буфера ?
|
|
|
Pasha
|
| Администратор
|
Пост N: 1972
Зарегистрирован: 23.05.05
|
|
Отправлено: 12.06.11 17:52. Заголовок: Добавил поддержку se..
Добавил поддержку seek-буфера. По умолчанию он выключен. Чтобы его включить, надо вызвать leto_setseekbuffer( nRecs ) для соответствующего индекса. Параметр - максимальное количество записей в буфере. Использование такого буфера для таблиц, в которых используется преимущественно индексный метод доступа, позволяет существенно сократить количество запросов к серверу. В моем тесте для не очень большой выборки число "попаданий" в буфер достигало тысяч.
|
|
|
alx_on
|
| постоянный участник
|
Пост N: 117
Зарегистрирован: 07.07.09
|
|
Отправлено: 14.06.11 09:24. Заголовок: Pasha пишет: Добави..
Pasha пишет: цитата: | Добавил поддержку seek-буфера |
| 1. поменялся фильтр (выполняемый на сервере) 2. поменялся scope 3. поменяли видимость удаленных записей в этих случаях буфер поиска необходимо сбрасывать (или не учитывать)
|
|
|
Pasha
|
| Администратор
|
Пост N: 1973
Зарегистрирован: 23.05.05
|
|
Отправлено: 14.06.11 12:57. Заголовок: alx_on пишет: 1. по..
alx_on пишет: цитата: | 1. поменялся фильтр (выполняемый на сервере) 2. поменялся scope 3. поменяли видимость удаленных записей в этих случаях буфер поиска необходимо сбрасывать (или не учитывать) |
| Сделаю. Заодно и для skipbuf, там тоже этого нет. set deleted перехватывать не получится, так что прийдется добавить этот флаг в буфер, и проверять его при использовании буфера. Сделаю отдельную структуру для буфера. Зодно хочется добавить статистику запросов для р.о на клиенте - количество запросов, количество попаданий в буфер
|
|
|
Pasha
|
| Администратор
|
Пост N: 1975
Зарегистрирован: 23.05.05
|
|
Отправлено: 14.06.11 19:10. Заголовок: Сделал Вызов leto_Se..
Сделал Вызов leto_SetSkipBuffer() и leto_SetSeekBuffer теперь возвращает статистику использования буфера для текущей р/о или индекса: сколько раз записи выбирались из буфера, а не запрашивались с сервера.
|
|
|
Pasha
|
| Администратор
|
Пост N: 1978
Зарегистрирован: 23.05.05
|
|
Отправлено: 04.07.11 18:02. Заголовок: Собрал letodb под wi..
Собрал letodb под win64 с помощью mingw64. Работает.
|
|
|
alx_on
|
| постоянный участник
|
Пост N: 118
Зарегистрирован: 07.07.09
|
|
Отправлено: 04.07.11 23:30. Заголовок: Pasha пишет: Собрал..
Pasha пишет: цитата: | Собрал letodb под win64 с помощью mingw64. Работает |
| у меня и раньше работало (правда MAC OS X 64-бита и gcc) есть какая то разница между mingw64 и gcc?
|
|
|
Sergey Spirin
|
| постоянный участник
|
Пост N: 520
Зарегистрирован: 25.12.07
|
|
Отправлено: 05.07.11 01:11. Заголовок: Pasha пишет: Собрал..
Pasha пишет: цитата: | Собрал letodb под win64 с помощью mingw64. Работает. |
| Паш, и чего, ни разу приведения pointer к int по всему коду не было? Абалдеть! P.S. Не советую тешиться
|
|
|
Ответов - 232
, стр:
1
2
3
4
5
6
7
8
9
10
11
12
All
[только новые]
|
|