Форум » LetoDB, HbNetio. » Leto DB Server (продолжение) » Ответить

Leto DB Server (продолжение)

alkresin: Только что открыл на Sourceforge новый проект - Leto DB Server - https://sourceforge.net/projects/letodb Это мультиплатформенный ( Windows, Unix/Linux ) сервер баз данных, предоставляющий клиентским программам доступ к dbf/cdx файлам, находящимся на удаленном сервере ( можно и на локальном компьютере запускать - в отладочных целях ). В общем, как ADS :). Проект - на стадии разработки, не все даже базовые функции еще реализованы, до оптимизации дело еще не дошло. Но работает :). Крутится у меня на сервере несколько дней, подключал до 15 клиентов, пока не падает. Мои программы работают с ним нормально. Преимущества по сравнению с обычным файл-сервером: 1) Безопасность - базы могут быть в каталоге, недоступном для клиентских компьютеров - никто их случайно не удалит и не повредит. 2) Поскольку базы открываются серверной программой, а не клиентской, ее целостности ничего не грозит при случайном отключении клиентского компьютера. 3) значительное уменьшение сетевого траффика. 4) Должен быть, по идее, выигрыш в скорости. 5) Возможность контроля за пользователями с помощью утилиты manage ( можно придумать и другие формы контроля ). 6) Можно будет сделать транзакции, stored procedures на Харборе, ... и вообще все в наших руках :). Кто хочет участвовать в разработке, тестировании - пишите.

Ответов - 316, стр: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 All

PSP: Pasha пишет: Вот аналог DateTime() с миллисекундами: Ok. Спасибо.

alkresin: PSP пишет: Кто-нибудь может проверить, работает ли FLock(): у меня при попытке блокировки с помощью FLock(), она возвращает .T., но не блокирует файл. DBInfo( DBI_ISFLOCK ) возвращает .F. и все операции блокировок/изменения работают. Пример в студию, пожалуйста. Я проверял - вроде и dbInfo() правильное значение возвращает, и flock() в параллельном процессе не блокирует файл ...

PSP: Код простейший: - первый процесс: FLock() --> .T., DBInfo( DBI_ISFLOCK ) --> .T. (процесс не завершаем). - второй процесс: FLock() --> .F., DBInfo( DBI_ISFLOCK ) --> .F., RLock() на любой записи --> .T. и спокойно можно писАть.


alkresin: - первый процесс: FLock() --> .T., DBInfo( DBI_ISFLOCK ) --> .T. (процесс не завершаем). - второй процесс: FLock() --> .F., DBInfo( DBI_ISFLOCK ) --> .F., RLock() на любой записи --> .T. и спокойно можно писАть. Ясно. А я только FLock() --> .F., DBInfo( DBI_ISFLOCK ) --> .F. проверил и успокоился :). Починим.

alkresin: - первый процесс: FLock() --> .T., DBInfo( DBI_ISFLOCK ) --> .T. (процесс не завершаем). - второй процесс: FLock() --> .F., DBInfo( DBI_ISFLOCK ) --> .F., RLock() на любой записи --> .T. и спокойно можно писАть. Проверил еще раз - Rlock() во втором процессе возвращает .f.: #include "dbinfo.ch" Function Main Local cPath := "//127.0.0.1:2812/" REQUEST LETO RDDSETDEFAULT( "LETO" ) use ( cpath+"dopsv" ) new shared ? flock() ? dbinfo( DBI_ISFLOCK ) inkey(0) go top ? rlock() inkey(0) return nil Может, у вас серверная часть старая ?

PSP: Ну что ж... плохо быть тупым... Все работает. Посыпаю голову пеплом... Спасибо, Александр, извините за бескойство.

alx_on: Привет Взял последний harbour На серверной части SCOPE просто игнорируются (для примера можно взять любую таблицу с индексом и поставить несуществующие скопы, будет бегать по ВСЕЙ таблице) Я поправил для себя и могу выложить изменения в CVS Просто интересно - может только у меня такое проявляется? Потому как никаких правок в harbour'е, влияющих на letodb не нашел

alx_on: Никто не сталкивался? Моя особенность? хм...

Andrey: alx_on пишет: Никто не сталкивался? Давай рабочий пример....

PSP: alx_on пишет: Никто не сталкивался? Моя особенность? Я не использую SCOPE. Ничего не могу сказать. Свяжитесь с Александром по почте.

alkresin: Давайте пример. Я сам Scope не пользуюсь. Когда-то проверял, вроде все работало.

goest: В тексте сервера есть небольшая ошибка в константах ставится SCOPE TOP и BOTTOM а в конце снимается 2 раза TOP возможно это ?

alx_on: alkresin пишет: Давайте пример Извините за долгий ответ (никак не могу выдрать маленький рабочий пример для повтора ошибки, но в большом проекте лажается) вот кусок кода (letofunc.c) static PHB_ITEM leto_KeyToItem( DBFAREAP pArea, const char *ptr, int iKeyLen, const char *szOrder ) { ... pInfo.itmOrder = NULL; pInfo.itmResult = hb_itemPutC( NULL, "" ); SELF_ORDINFO( (AREAP)pArea, DBOI_KEYTYPE, &pInfo ); KeyType = *( hb_itemGetCPtr( pInfo.itmResult ) ); если вместо "pInfo.itmOrder = NULL;" поставить "pInfo.itmOrder = hb_itemPutC( NULL, имя ордера );" то все работает. С чем связано понять пока не могу... Плюс сейчас тестируем (5-10 тестировщиков на реальной базе) - раз или два в день letodb падает (может быть уже последствия исправления ошибки, указанной выше, очень мало времени на глубокий анализ проблемы, да повторяется не стабильно): User: 192.168.170.147 TST-NURGALIEVA personal.exe Command: goto;2049;-1;;A; Table: \refer\pymnt.dbf Unrecoverable error 6005: Exception error: %s. Unrecoverable error 9011: User: (null) (null) (null) Command: open;01;6;/personal\data\default\persn___.dbf;PERSN;TF;RU866; Unrecoverable error 6005: Exception error: %s goest пишет: В тексте сервера есть небольшая ошибка а где конкретно?

alkresin: alx_on пишет: pInfo.itmOrder = NULL; pInfo.itmResult = hb_itemPutC( NULL, "" ); SELF_ORDINFO( (AREAP)pArea, DBOI_KEYTYPE, &pInfo ); KeyType = *( hb_itemGetCPtr( pInfo.itmResult ) ); если вместо "pInfo.itmOrder = NULL;" поставить "pInfo.itmOrder = hb_itemPutC( NULL, имя ордера );" то все работает. С чем связано понять пока не могу... Если ordinfo не получает имя тэга в itmOrder, он использует текущий. Когда leto_KeyToItem вызывается из leto_Seek, все работает правильно, т.к. в leto_Seek предварительно устанавливается текущий тэг ( leto_Setfocus ), а вот в leto_Scope это не происходит, отсюда и неверная работа ordinfo и, соответственно, leto_KeyToItem. Поэтому надо добавить в leto_KeyToItem четвертый параметр - имя ордера и поставить: if( szOrder ) pInfo.itmOrder = hb_itemPutC( NULL, szOrder ); Из leto_Seek передавать NULL, а из leto_Scope - szOrder.

alkresin: goest пишет: В тексте сервера есть небольшая ошибка в константах ставится SCOPE TOP и BOTTOM а в конце снимается 2 раза TOP Не нашел я такого места.

PSP: На CVS обновился LetoDB. Добавились функции для работы с общими (shared) переменными. Могут быть очень полезны. LETO_VARSET( cGroupName, cVarName, xValue[, nFlags[, @xRetValue]] ) --> lSuccess LETO_VARGET( cGroupName, cVarName ) --> xValue LETO_VARINCR( cGroupName, cVarName ) --> nValue LETO_VARDECR( cGroupName, cVarName ) --> nValue LETO_VARDEL( cGroupName, cVarName ) --> lSuccess LETO_VARGETLIST( [cGroupName] ) --> aList 6. Variables management Letodb allows to manage variables, which are shared between applications, connected to the server. Variables are separated into groups and may be of logical, integer or character type. You can set a variable, get it, delete or increment/decrement ( numerical, of course ). All operations on variables are performed consecutively by one thread, so the variables may work as semaphores. See the functions list for a syntax of appropriate functions and tests/test_var.prg for a sample. Letodb.ini may contain lines to determine the maximum number of variables and a maximum size of a text variable. У меня вопрос к Александру: если приложение, создавшее какую-либо переменную, аварийно завершается (связь с сервером исчезает), сервер продолжает хранить эту переменную или уничтожает?

alkresin: PSP пишет: если приложение, создавшее какую-либо переменную, аварийно завершается (связь с сервером исчезает), сервер продолжает хранить эту переменную или уничтожает? Переменная остается. Но я собираюсь добавить флаг для leto_Varset(), который определит создаваемую переменную как подлежащую автоматическому удалению после завершения работы создавшего ее приложения. Сейчас я эти функции использую следующим образом: у меня есть программы, расположенные на удаленных производственных участках, собирающие информацию с датчиков и складывающие обсчитанные результаты в dbf. На тех же компьютерах стоит letodb и через него в офисе мы получаем эти результаты. А через "shared variables" передается оперативная информация о состоянии датчиков и самой программы.

PSP: alkresin пишет: Но я собираюсь добавить флаг для leto_Varset(), который определит создаваемую переменную как подлежащую автоматическому удалению после завершения работы создавшего ее приложения. Имхо, нужно. Сейчас я эти функции использую следующим образом: у меня есть программы, расположенные на удаленных производственных участках, собирающие информацию с датчиков и складывающие обсчитанные результаты в dbf. На тех же компьютерах стоит letodb и через него в офисе мы получаем эти результаты. А через "shared variables" передается оперативная информация о состоянии датчиков и самой программы. Очень полезные функции. Спасибо!

alx_on: Заметил неприятность Ошибка обновления буфера записи после SET RELATION Проявляется, например, так (упрощенно): use "alias1", "alias2" ставим ордер ("CODE") на alias1 (ключ "FIELD->CODE", {"CODE","C",6,0}) SELECT alias2 SET RELATION TO alias1->CODE INTO alias1 SELECT alias1 снова ставим ордер ("CODE") !--- SEEK "000001" запись найдена, RECNO правильно чтение любого поля возвращает старое значение (до поиска) !--- Сделав, например, два раза подряд SEEK снова все хорошо или сразу после "SET RELATION" прочитав любое поле Пока не разбирался в чем дело. Завтра (О! сегодня) буду посмотреть. Сбивает с толку то, что лажается в странной ситуации - "папа" никак не учавствует! Т.е. relation вообще не должен влиять

alx_on: Разобрался с RELATION вот пример текущего кода (leto1.c): static ERRCODE letoGoTop( LETOAREAP pArea ) { char sData[32], * ptr; HB_TRACE(HB_TR_DEBUG, ("letoGoTop(%p)", pArea)); if( pArea->uiUpdated ) leto_PutRec( pArea ); sprintf( sData,"goto;%lu;-1;%s;%c;\r\n", pArea->hTable, (pArea->pTagCurrent)? pArea->pTagCurrent->TagName:"", (char)( (hb_setGetDeleted())? 0x41 : 0x40 ) ); if ( !leto_SendRecv( pArea, sData, 0, 1021 ) ) return FAILURE; ptr = leto_firstchar(); leto_ParseRec( pArea, ptr ); pArea->ptrBuf = NULL; SELF_SKIPFILTER( ( AREAP ) pArea, 1 ); if( pArea->area.lpdbRelations ) return SELF_SYNCCHILDREN( ( AREAP ) pArea ); else return SUCCESS; } после DBGOTOP() на родительской таблице выполнение DBSEEK() на подчиненной лажается (находит не ту запись) Если сделать так: static ERRCODE letoGoTop( LETOAREAP pArea ) { char sData[32], * ptr; HB_TRACE(HB_TR_DEBUG, ("letoGoTop(%p)", pArea)); sprintf( sData,"letoGoTop(%p)", pArea ); leto_writelog(sData,0); if( pArea->uiUpdated ) leto_PutRec( pArea ); sprintf( sData,"goto;%lu;-1;%s;%c;\r\n", pArea->hTable, (pArea->pTagCurrent)? pArea->pTagCurrent->TagName:"", (char)( (hb_setGetDeleted())? 0x41 : 0x40 ) ); leto_writelog(sData,0); if ( !leto_SendRecv( pArea, sData, 0, 1021 ) ) return FAILURE; ptr = leto_firstchar(); leto_writelog(ptr,0); leto_ParseRec( pArea, ptr ); pArea->ptrBuf = NULL; if( pArea->area.lpdbRelations ) { if( SELF_SYNCCHILDREN( ( AREAP ) pArea ) != SUCCESS ) return FAILURE; } SELF_SKIPFILTER( ( AREAP ) pArea, 1 ); return SUCCESS; } Т.е. переставить местами SELF_SYNCCHILDREN и SELF_SKIPFILTER, то все работает Вопрос к alkresin: я правильно понял проблему или это просто так повезло в моем случае? PS остались моменты, которые еще не смотрел подробно: 1. после DBGOTO(LASTREC()+100) на родительской таблице - на подчиненной должно тоже встать на LASTREC()+1. Этого не происходит (встает на запись, найденную по пустому ключю, в драйвере CDX все ок). Причем именно GOTO, остальные команды перемещения отрабатывают правильно. 2. OrdKeyVal() на записи за пределами таблицы (LASTREC()+1) в драйвере CDX возвращает NIL. LetoDB некую строку (она правильная, но здесь несовместимость со стандартным драйвером CDX)

alkresin: alx_on пишет: Т.е. переставить местами SELF_SYNCCHILDREN и SELF_SKIPFILTER, то все работает Вопрос к alkresin: я правильно понял проблему или это просто так повезло в моем случае? Думаю, что просто повезло. Чтобы решить проблему, надо во всех операциях перемещения вставить строку pArea->lpdbPendingRel = NULL; Дело в том, что когда в родительской области происходит перемещение этот элемент структуры child area устанавливается ( см. letoChildSync ) и когда мы читаем запись из child area, то при установленном pArea->lpdbPendingRel происходит перемещение в child области.

alx_on: alkresin Примерно так? static ERRCODE letoGoTop( LETOAREAP pArea ) { char sData[32], * ptr; HB_TRACE(HB_TR_DEBUG, ("letoGoTop(%p)", pArea)); if( pArea->uiUpdated ) leto_PutRec( pArea ); sprintf( sData,"goto;%lu;-1;%s;%c;\r\n", pArea->hTable, (pArea->pTagCurrent)? pArea->pTagCurrent->TagName:"", (char)( (hb_setGetDeleted())? 0x41 : 0x40 ) ); if ( !leto_SendRecv( pArea, sData, 0, 1021 ) ) return FAILURE; ptr = leto_firstchar(); leto_ParseRec( pArea, ptr ); pArea->ptrBuf = NULL; SELF_SKIPFILTER( ( AREAP ) pArea, 1 ); if( pArea->area.lpdbRelations ) { if( SELF_SYNCCHILDREN( ( AREAP ) pArea ) != SUCCESS ) return FAILURE; } pArea->lpdbPendingRel = NULL; return SUCCESS; } PS Вставлять вообще ВЕЗДЕ или только после SELF_SYNCCHILDREN? PPS Сама функция letoChildSync() не сбрасывает lpdbPendingRel. Ее тоже необходимо поправить? PPPS Для текущей версии harbour вместо HB_LONG используется HB_MAXINT. У себя я поправил (иначе падало. Например в UpdateRec обработка числовых полей HB_FT_LONG и HB_FT_FLOAT)

alkresin: Примерно так? Лучше поставить в начале функции. PS Вставлять вообще ВЕЗДЕ или только после SELF_SYNCCHILDREN? Во всех функциях перемещения. SELF_SYNCCHILDREN тут ни при чем, так как она вызывается для синхронизации детей текущей area. PPS Сама функция letoChildSync() не сбрасывает lpdbPendingRel. Ее тоже необходимо поправить? Нет, letoChildSync() устанавливает lpdbRelations для себя, ее трогать не надо. Эта штука (lpdbRelations) обнуляется для того, чтобы area, где она установлена родителем, не перемещала текущую запись в соответствии с положением родителя.

alkresin: alkresin пишет: Чтобы решить проблему, надо во всех операциях перемещения вставить строку pArea->lpdbPendingRel = NULL; Выложил сегодня эти изменения на CVS

alx_on: alkresin Выложил свои изменения (в продолжение темы relations). 1. DBSKIP(0) ничего не делал (в принципе, нормально для родителя, но дитя должно перемещаться). 2. DbAppend() не синхронизировал записи 3. RECNO() возвращал значение до синхронизации с родителем (также блокировка) Поправлена установка фильтра с национальными символами Изменил HB_LONG на HB_MAXINT (вопрос: на xHarbour это компиляется?)

alkresin: alx_on пишет: Изменил HB_LONG на HB_MAXINT (вопрос: на xHarbour это компиляется?) Не знаю, как на xHarbour, а на той версии Harbour, которой я пользуюсь, HB_MAXINT не определен ...

alkresin: Проверил xHarbour - там тоже HB_MAXINT не определен.

alx_on: alkresin пишет: Не знаю, как на xHarbour, а на той версии Harbour, которой я пользуюсь, HB_MAXINT не определен ... я пользуюсь с SVN 2 варианта либо нет HB_MAXINT под определенную платформу (так уже было) либо придется проверять версию (начиная с какой?) под xHarbour могу поправить (только проверить не смогу) PS кстати, я запускаю letodb под MacOSX (10.6) - все работает

alkresin: alx_on пишет: я пользуюсь с SVN А я пользуюсь "Changelog 2008-09-17 18:04" :) и в ближайшее время переходить на более новую не планирую. Давайте вернем это дело назад. Думаю, я не один такой, кто еще не перешел на Harbour-2.

alx_on: alkresin пишет: Давайте вернем это дело назад Может, конечно, это совпадение, но у меня с HB_LONG падает Обрамим проверками на Harbour-2 По типу: #if defined (__XHARBOUR__) || !defined(__HARBOUR__) || ( (__HARBOUR__ - 0) < 0x020000 ) HB_LONG lVal #else HB_MAXINT lVal #endif или так (в самом начале): #if !defined (HB_MAXINT) #define HB_MAXINT HB_LONG #endif В течение часа выложу

alkresin: alx_on пишет: #if !defined (HB_MAXINT) #define HB_MAXINT HB_LONG #endif Так не получится, потому что HB_MAXINT определен через typedef и defined (HB_MAXINT) всегда будет false.

alx_on: alkresin пишет: Так не получится, потому да, я уже заметил :) значит первый вариант

alx_on: alkresin выложил

Andrey: alx_on пишет: PS кстати, я запускаю letodb под MacOSX (10.6) - все работает Круто ! Это просто фантастика ! Харбор на маке... А программа тоже под MacOSX работает ?

alx_on: Andrey пишет: А программа тоже под MacOSX работает ? Да

alx_on: alkresin выложил новые изменения... PS вопрос: в связи с чем индексы каждый раз переоткрываются для уже открытой базы (hs_openindex)? Можно ли это оптимизировать?

alkresin: alx_on пишет: PS вопрос: в связи с чем индексы каждый раз переоткрываются для уже открытой базы (hs_openindex)? Хм... Я этого не замечал, наверное потому что дополнительные ( не compound ) индексы использую только как временные, для одного сеанса работы и не разделяю их с другими экземплярами программы. Надо как-то исправить, конечно.

Pasha: Перевел документацию на русский язык См. readme_rus.txt

Andrey: Pasha пишет: Перевел документацию на русский язык Спасибо Паша !

leo: Использует ли кто-то в реальных проектах Leto DB Server? Насколько надежно он ведет себя в работе? Стоит ли на него переходить?

Dima: leo Такой же вопрос можно задать и про ADS. Лучше всего попробовать самому Leto DB Server.

sashaBG: Привет Всем ! Уже 5 месяцов как 3 из моих клиентов перешли на мою новую версию бухучета пока никаких проблем не замечено Я использую MiniGUI Ext + Harbour + LetoDB + RPC функциональност от HBNETIO Есть серверная часть , в которой включен сервер с HBNETIO , и мой RPC функции . Заоодно етот модуль управляет и LetoDB ( Start , Stop , Manager.exe , просмотр Log файла и т.д.) ну и Клиент Моя программа зовется "АЛМА" я даже в честь етого сервера новую версию окрестил "АЛМА ЛЕТО"

sashaBG: alx_on Я большой фанат МАКОВ , у меня Хакинтош (ASUS P5QL-PRO , C2D7200 , GF9500 , Leopard 10.5.8) все работает без проблем наверное год и Macbook Pro 17'' У тебя программа консольная на МАКЕ или что то другое ?

alx_on: sashaBG Harbour + ( QT + HbQt ) Win,Linux,MacOSX

alx_on: alkresin Александр, помогите плз разобраться. Может у Вас появится идея. У нас сейчас активно тестируется работа с LetoDB (сервер на win) и стабильно раз в день (два раза через день) лето падает. Причем в самых неожиданных местах. Тестеров 5-10 человек. Одновременно открытых таблиц (на всех) 15-200. Например, одно место: Unrecoverable error 6005: Exception error: %s Exception Code:C0000005 Exception Address:004AAB64 EAX:00000000 EBX:0137BF3C ECX:013F38BC EDX:00000000 ESI:013F39C0 EDI:0000000D EBP:003D66E4 CS:EIP:001B:004AAB64 SS:ESP:0023:01B8F910 DS:0023 ES:0023 FS:003B GS:0000 Flags:00010202 CS:EIP: 0F B7 04 78 89 2C 24 01 D0 89 44 24 04 E8 0A 78 SS:ESP: 003D66E4 018E4604 01B8FC60 004E1B37 018C4B74 01B9147C 01B914DC 004E1B37 01B914DC 00000008 01B8FC60 0000000A 00000000 003C653C 01B99535 0000000F Command: ord;02;18949;opdate;29579; Я нашел это место - оказалось в драйвере CDX (последний harbour из SVN) в функции hb_dbfGetValue() case HB_FT_DATE: if( pField->uiLen == 3 ) { hb_itemPutDL( pItem, HB_GET_LE_UINT24( pArea->pRecord + pArea->pFieldOffset[ uiIndex ] ) ); } else if( pField->uiLen == 4 ) { hb_itemPutDL( pItem, HB_GET_LE_UINT32( pArea->pRecord + pArea->pFieldOffset[ uiIndex ] ) ); } else { hb_itemPutDS( pItem, ( char * ) pArea->pRecord + pArea->pFieldOffset[ uiIndex ] ); <---- GPF!!! при попытке взять "pArea->pFieldOffset[ uiIndex ]" } break; Но при таком же тесте в течении 2-3 дней без лето ничего не падает.

sashaBG: alx_on У меня тоже такое случалось когда собираю LetoDB с версиями после 2.0.0 поетому я пока его собираю с Harbour 2.0.0 ChangeLog 13372 и не падает

alx_on: alkresin пишет: дополнительные ( не compound ) индексы использую только как временные, для одного сеанса работы и не разделяю их с другими экземплярами программы У меня это, к сожалению, норма Т. е. индексы всегда хранятся отдельно от таблиц (в отдельном каталоге) и они открываются принудительно каждый раз при открытии таблиц

alx_on: sashaBG пишет: Harbour 2.0.0 ChangeLog 13372 Почему именно эта ревизия?

alkresin: alx_on пишет: У нас сейчас активно тестируется работа с LetoDB (сервер на win) и стабильно раз в день (два раза через день) лето падает. В связи с тем, что сказал sashaBG, может, стоит попробовать откомпилировать сервер с другой версией Harbour ... У меня сейчас работают с letodb сервером 25 - 35 пользователей, 10 - 15 разных приложений, 40 - 60 dbf файлов. До недавнего времени использовал letodb от августа 2009, он практически не падал, было, пожалуй 2 таких случая за полгода. Когда недели 2-3 назад перешел на последнюю ( с CVS ) версию letodb, он стал падать раз в несколько дней, причем, как я заметил, это обычно происходило во время присоединения нового пользователя, и, как мне кажется, в том случае, если это Windows станция и пользователь запускал программу сразу после включения компьютера, как только появлялся рабочий стол, не дожидаясь полного окончания загрузки Windows. Я так и не понял пока, отчего это могло происходить. Сделал несколько мелких правок в hbip.c b letofunc.c ( Changelog 2010-05-25 11:40 UTC+0300 ), теперь жду результата, за прошедшие 3 дня еще ( тьфу-тьфу ) не падал. Я нашел еще одно место, которое потенциально может вызывать проблемы. Как вы знаете, в letodb сервере 2 потока. Один слушает сеть, опрашивает открытые сокеты, принимает с них информацию, анализирует команды и выполняет те из них, которые можно обработать на чистом С, без вызова RDD и прочих Harbour level функций, работающих с vm, стеком. 2-й поток обрабатывает остальные команды. Так вот, сейчас первый поток вызывает и функцию leto_CloseUS() - закрытие клиента, которая, если есть еще у него незакрытые areas, закрывает их, т.е. выполняет действия, предназначеннные для 2-го потока, что теоретически может вызвать неприятные коллизии. Это может происходить, если вы "убиваете" пользователя из manage или если связь с ним по какой-то причине внезапно обрывается ( при нормальном завершении задачи Harbour сам закрывает открытые areas и такого не происходит ).

alkresin: ( В продолжение к предыдущему ) Ну и, раз у вас индексы открываются так, как вы описали, то, учитывая эту ошибку в hs_openindex, даже не представляю, как оно вообще у вас работает...

sashaBG: alx_on Я не такой спец в C и поетому не стал копть в GPF а просто вернулся на stable версию Harbour с www.harbour-project.org Да конечно и мне тоже хочется скомпилировать все одной и той же весрии Harbour . Может господин Кресин действительно поможет !

alx_on: alkresin пишет: даже не представляю, как оно вообще у вас работает... Я вообще не представлял что оно будет на работать на маке, но ведь работает хотя в коде есть конкретные вставки только под win и linux (я не вникал что там, приоритет пока на вин-платформу) по поводу индексов: просто переоткрывает и память переинициализирует (вопрос насколько корректно?) стоит попробовать откомпилировать сервер с другой версией Harbour не могу - многое завязано на новой версии (например, HbQT) Может это быть связано с массовой переделкой типов (ULONG на HB_MAXINT и т.д.)? если связь с ним по какой-то причине внезапно обрывается вот, кстати, по поводу связи: если хоть на миг связь прерывается (например, комп почти успел уйти в сон, но почти успели двинуть мышой ), то все соединения с лето на клиенте рвутся (соответственно ни работать дальше нельзя, ни закрыть нормально, куча ошибок выходит на каждую открытую таблицу)

alkresin: alx_on пишет: не могу - многое завязано на новой версии (например, HbQT) Так перекомпилите только сервер, клиенты пусть остаются как есть. Может это быть связано с массовой переделкой типов (ULONG на HB_MAXINT и т.д.)? Если вы перекомпилите сервер с другой версией Harbour и он перестанет падать, тогда будет иметь смысл подумать об этом. вот, кстати, по поводу связи: если хоть на миг связь прерывается (например, комп почти успел уйти в сон, но почти успели двинуть мышой ), то все соединения с лето на клиенте рвутся Хм.. А что, связь прерывается при уходе в сон ? Я сейчас специально 2 раза вышел при открытой программе в ждущий режим ( через Пуск...Выключение ) - после пробуждения все работало как прежде. А вообще при прерывании связи клиент принудительно отключается, а что еще с ним делать ?

alx_on: alkresin пишет: Если вы перекомпилите сервер с другой версией Harbour Надо будет попробовать. На какой версии остановиться? Я сейчас специально 2 раза вышел при открытой программе в ждущий режим странно... у меня все отвалилось при прерывании связи клиент принудительно отключается, а что еще с ним делать ? Подождать какое то время, например, и переподключать. Но это так, мечты... PS может быть такая ситуация: на сетевом уровне пакет (строка с командой) пришла не полностью?

alkresin: alx_on пишет: Надо будет попробовать. На какой версии остановиться? Предлагаю какую-нибудь до появления mt, у меня, например, 1.01 стоит. PS может быть такая ситуация: на сетевом уровне пакет (строка с командой) пришла не полностью? Такая ситуация предусмотрена. Сервер опрашивает сокет, пока не обнаружит конца пакета. Сокет отключается и клиент удаляется только в случае если в результате опроса сокета была возвращена ошибка.

alx_on: alkresin пишет: Сокет отключается и клиент удаляется Имелось в виду падение сервера, т.е. разбор неполной строки с командой

alx_on: alkresin пишет: Предлагаю какую-нибудь до появления mt, у меня, например, 1.01 стоит Подскажете точные ключи компиляции для винды (чтобы быть уверенным в результате) можно и для linux И плюс для самого лета PS там на компилятор есть ограничение? Я использую mingw почти последний

alkresin: alx_on пишет: Подскажете точные ключи компиляции для винды (чтобы быть уверенным в результате) можно и для linux Я не ставлю никаких своих дополнительных ключей, что есть в стандартных файлах конфигурации, то и использую. То же для лета - один к одному как на CVS. PS там на компилятор есть ограничение? Я использую mingw почти последний С mingw не пробовал, ничего не могу сказать. Клиентов я компилирую с Borland 5.5, а сервер у меня на Линукс.

alx_on: sashaBG пишет: собираю с Harbour 2.0.0 ChangeLog 13372 Попробовал с 2.0 Не компиляет! funcleto.h:138: error: redefinition of typedef ‘HB_ERRCODE’ harbour2.0/include/hbapi.h:473: error: previous declaration of ‘HB_ERRCODE’ was here Придется разбираться :)

alkresin: alx_on пишет: Имелось в виду падение сервера, т.е. разбор неполной строки с командой Разбора неполной строки быть не может - протокол предусматривает определение конца пакета и пока этот конец не будет определен, разбор строки не начнется.

alx_on: alkresin пишет: Я не ставлю никаких своих дополнительных ключей, что есть в стандартных файлах конфигурации, то и использую В смысле просто make?

alkresin: alx_on пишет: В смысле просто make? В той версии, которой я пользуюсь, еще есть make_b32.bat и make_b32.mak, там еще не используется gnu make :)

alkresin: Это для Windows. А для Линукс - да, просто make, и перед ним устанавливаю несколько переменных окружения: export HB_ARCHITECTURE=linux export HB_COMPILER=gcc export HB_GT_LIB=gtcrs

alkresin: Посмотрел внимательнее hs_openindex, там вроде бы все в порядке, ничего не переоткрывается, ничего не переинициализируется.

alkresin: Павел, что-то после ваших сегодняшних изменений "for compatibility with older xHarbour versions" у меня перестало компилироваться: source\server\server.prg(110) Error F0029 Can't open #include file: 'hbextcdp.ch' ... Error: Unresolved external '_hb_GetSetStructPtr' referenced from C:\MYAPPS\LETODB\OBJ\B32\LETOFUNC.OBJ

Pasha: Я проверял сборку для Harbour с SVN, поэтому получилась такая неувязка. с _hb_GetSetStructPtr понятно, я сейчас поправлю. У меня Harbour 1.х нет, но суть ясна. А с source\server\server.prg(110) какие-то чудеса, а поскольку чудес не существует, видимо баг в препроцессоре Я собирал letodb с xharbour 1.01, и на строке 105, в ветке для Harbour, которую xHarbour не должен компилировать: #if ( (HB_VER_SVNID - 0) > 11796 ) получил ошибку на #if я заменил конструкцию: #if defined(HB_VER_SVNID) #if ( (HB_VER_SVNID - 0) > 11796 ) #define __HB_EXT_CDP__ #endif #endif на идентичную: #if defined(HB_VER_SVNID) && ( (HB_VER_SVNID - 0) > 11796 ) #define __HB_EXT_CDP__ #endif ошибка в xharbour исчезла, но появилась непонятная ошибка в Harbour Я конечно верну все назад, но фокусы с препроцессором непонятны

alx_on: alkresin пишет: Посмотрел внимательнее hs_openindex, там вроде бы все в порядке Я вставил отладочные сообщения - hs_openindex каждый раз отрабатывает, т.е. OrdListAdd( cBagName ) OrdSetFocus( OrdCount() ) хотя таблица с таким индексным файлом уже открыта и используется

alkresin: Pasha пишет: А с source\server\server.prg(110) какие-то чудеса, а поскольку чудес не существует, видимо баг в препроцессоре Да, по-видимому, в тех версиях такие конструкции вызывают ошибки. Я уже сталкивался с этим.

alkresin: alx_on пишет: Я вставил отладочные сообщения - hs_openindex каждый раз отрабатывает, т.е. OrdListAdd( cBagName ) OrdSetFocus( OrdCount() ) хотя таблица с таким индексным файлом уже открыта и используется Да, отрабатывает. Но если вы посмотрите на реализацию OrdListAdd() d dbfcdx и dbfntx ( я вчера посмотрел :) ), то увидите, что там проверяется, открыт ли уже этот индекс, и, если открыт, не делается ничего.

alx_on: Нашел интересную зависимость под win Если стоит "microsoft visual C++ 2008 Redistributable - x86 9.0.21022" то лето падает (как мной описано постами выше) если удалить (стандартно), то не падает (конечно, может и неверно лето работает, например, ошибки по памяти остаются, но молча пропускаются )

alkresin: alx_on пишет: Если стоит "microsoft visual C++ 2008 Redistributable - x86 9.0.21022" то лето падает (как мной описано постами выше) если удалить (стандартно), то не падает Интересно... А каким С компилятором у вас letodb скомпилирован ? MSVS ? Если да, то той же версии, что и Redistributable ?

alx_on: alkresin пишет: С компилятором у вас letodb скомпилирован ? MinGW Но суть не в этом. Я нашел проблему! По крайней мере одну из... :) При передаче значений полей возникает путаница, если кол-во полей в таблице > 255 Там такой бардак начинается, что диву даешься как это все работало Попытаюсь сегодня выложить предварительные исправления PS Александр, вопрос: в старом harbour и xHarbour есть функции (правильно! работающие под разные ОС) hb_osPathSeparator() hb_osDriveSeparator() hb_osNewLine()

alkresin: alx_on пишет: PS Александр, вопрос: в старом harbour и xHarbour есть функции (правильно! работающие под разные ОС) hb_osPathSeparator() hb_osDriveSeparator() hb_osNewLine() Функции есть, ну а правильно они работают или нет - не проверял. Наверное, правильно :).

alx_on: alkresin пишет: Функции есть Предлагаю их использовать вместо прямых указаний "/", "\" и перевода строк все пути в коде сервера переводить на нативный вариант текущей оси сервера (путаница возникает при использовании на клиентских местах разных ОС)

alkresin: Предлагаю их использовать вместо прямых указаний "/", "\" и перевода строк Не возражаю. А перевод строк где нам нужен ? все пути в коде сервера переводить на нативный вариант текущей оси сервера Так они переводятся, только с использованием напрямую "/", "\"

alx_on: alkresin пишет: А перевод строк где нам нужен В логах, например Так они переводятся, Не везде Вопрос: для чего в letoOrderCreate() после успешного создания индекса нужно делать SELF_GOTOP()? Во первых это лишний вызов (у меня в CDX-файле штук 10 ордеров и 10 gotop соответственно мне не нужны, после создания последнего может и надо, и то не в моем случае) Столкнулся со странной ситуацией - на ОДИН файл не может создать индекс (причем, подобные файлы с такой же структурой - ок) именно "return SELF_GOTOP( ( AREAP ) pArea )" возвращает ошибку! upd! Ошибся! Сделал SELF_GOTOP( ( AREAP ) pArea ); return SUCCESS; - тоже самое Ничего не понимаю

alkresin: Вопрос: для чего в letoOrderCreate() после успешного создания индекса нужно делать SELF_GOTOP()? Потому что так ведет себя эта функция во всех RDD. именно "return SELF_GOTOP( ( AREAP ) pArea )" возвращает ошибку! Ошибку - в смысле run-time error с соответствующими gencode, subcode ? Если так, то что дает return SUCCESS, если эта runtime error уже произошла во время исполнения SELF_GOTOP ...

alx_on: alkresin пишет: во время исполнения SELF_GOTOP В чем может быть проблема? в функциях letoGoTop() в leto1.c leto_Goto() в letofunc.c ошибки не возникают...

alkresin: В чем может быть проблема? в функциях letoGoTop() в leto1.c leto_Goto() в letofunc.c ошибки не возникают... Как я понял, эта ошибка происходит у вас при создании одного определенного индекса - т.е. сразу после его создания программа вываливается, так ? Значит, letoGoTop() для этого индекса не вызываются, или я не так понял ? А вот почему именно этот индекс вызывает ошибку надо смотреть. Создался он на сервере или нет, нормальный ли он ( открывается ли с dbfcdx ), какую именно ошибку вернул сервер. Мне, чтобы предметно об этом говорить, нужен самодостаточный пример, чтоб я мог его воспроизвести.

alx_on: alkresin пишет: сразу после его создания программа вываливается, так ? да Значит, letoGoTop() для этого индекса не вызываются только что еще раз проверил - вызывается Создался он на сервере или нет, нормальный ли он ( открывается ли с dbfcdx ) да и да самодостаточный пример попытаюсь сделать PS пока баловался - сделал нечаянно тот же самый индекс с параметром DESCENDING - прошло без ошибок

alkresin: В присланном вами test.dbf есть "нехорошая запись" ( recno() = 61 ) с несимвольной информацией - похоже, битая. После индексирования она становится 1-й и при Gotop() на нее получается ошибка - этим объясняется, почему с descending все работает ( первой становится другая запись ). После удаления этой записи и упаковки все работает нормально. Это, впрочем, не отменяет того факта, что ошибка возвращаться не должна - надо смотреть, в чем дело.

alkresin: Исправил я это дело, проблема была в битом поле типа DATE. Кстати, Александр, начал я смотреть ваши изменения - что-то вы в common_c.c форматирование сбили, там теперь разделитель строк не r\n, а \r\r\n

alx_on: alkresin пишет: разделитель строк не r\n, а \r\r\n Знаю :) я уже пытался выложить изменения, но меня опередили и теперь опять синхронизирую уффф, выложил проверьте плз

alkresin: уффф, выложил проверьте плз С common_c.c все в порядке.

alx_on: alkresin пишет: Исправил я это дело, проблема была в битом поле типа DATE. Может быть более жесткую проверку сделать (только цифры)? Может возникнуть аналогичная ситуация, но символ будет, например, больше пробела

alkresin: Может быть более жесткую проверку сделать (только цифры)? Может возникнуть аналогичная ситуация, но символ будет, например, больше пробела Нет особой необходимости. Вообще говоря, там достаточно было добавить проверку на \0, беда была именно в этом. Сервер передавал 8 нулей из битой записи, а клиент, а ведь \0 в первом байте - признак пустого поля. Клиент, обнаружив его, начинал читать следующее поля со следующего байта - и запутался.

santy: после изменений в файле funcleto.h #define hb_cdp_page hb_cdppage() #if defined(HB_ERRCODE) typedef HB_ERRCODE ERRCODE; #endif не компилится в xHarbour (121_6714) если вернуть назад, всё нормально проходит перед этим была одна ошибка в препроцесоре в файле server.prg, она и осталась, причина ошибки пока непонятна.

alkresin: Александр, после последних изменений появилась проблема ( с 2010-06-01 16:45 UTC+0300 Alexander Kresin ) работает нормально, я сейчас проверил. См. сообщение на letodb-developers@lists.sourceforge.net: In test_ta.prg i add dbskip() ... AddNakl( 1, Date(), { 1400.5, 28632.28, 800.51 } ) AddNakl( 2, Date(), { 58003, 930.5 } ) ? "Records has been added" dbskip() ... and get Error LETO/1000 Data type error ... and letodb_crash.log Сервер падает. Где-то у вас ошибка закралась...

alkresin: И еще вопрос по изменениям в протоколе: он изменился только для файлов с количеством полей > 256, или для всех ? Т.е., могу ли я компилировать приложения с новой версией, не трогая сервер ( у меня нет файлов с таким большим количеством полей ) ?

alx_on: alkresin пишет: могу ли я компилировать приложения с новой версией Да. Фактически это не изменение, а исправление Ошибку с DbSkip() поправил (тупо else пропустил как то )

alkresin: А на CVS исправления еще не запостили ?

alx_on: alkresin пишет: А на CVS исправления еще не запостили ? Выложил У меня все равно где то падает собака! Поймать не могу (переход на harbour 1.01 для меня - -как совсем крайний случай :) )

alkresin: Так а падает на harbour 1.01 или не проверяли ? Я согласен, что откат на старую версию - не выход, но такая проверка может подтолкнуть в правильном направлении. P.S. Падает и без установленных MSVS Redistributable ?

alx_on: alkresin пишет: Так а падает на harbour 1.01 или не проверяли ? Пока руки не дошли P.S. Падает и без установленных MSVS Redistributable ? Скорее всего молча пропускает ошибки Потому как с MSVS Redistributable отладчик (gdb) показывает ошибку примерно такого плана: неверный вызов (или неверные параметры вызова, точно не помню) С-функций (или библиотечных) Т.е. более жесткая проверка параметров вызова стандартных библиотечных функций

alx_on: Проявляется при интенсивной нагрузке с одной машины (3 задачи с обработкой больших файлов, десятки тысяч записей) Два падение на win-сервере 1. (gdb) bt #0 0x0041cb21 in dlmalloc () #1 0x0028670c in ?? () Backtrace stopped: previous frame inner to this frame (corrupt stack?) Dump of assembler code for function dlmalloc: 0x0041cab0 <+0>: push %ebp 0x0041cab1 <+1>: push %edi 0x0041cab2 <+2>: push %esi 0x0041cab3 <+3>: push %ebx 0x0041cab4 <+4>: sub $0x7c,%esp 0x0041cab7 <+7>: mov 0x90(%esp),%ebx 0x0041cabe <+14>: cmp $0xf4,%ebx 0x0041cac4 <+20>: ja 0x41cb40 <dlmalloc+144> 0x0041cac6 <+22>: cmp $0xa,%ebx 0x0041cac9 <+25>: ja 0x41cbf0 <dlmalloc+320> 0x0041cacf <+31>: mov 0x527660,%esi 0x0041cad5 <+37>: mov $0x2,%ecx 0x0041cada <+42>: mov $0x2,%edx 0x0041cadf <+47>: mov $0x10,%ebx 0x0041cae4 <+52>: mov %esi,%eax 0x0041cae6 <+54>: shr %cl,%eax 0x0041cae8 <+56>: test $0x3,%al 0x0041caea <+58>: je 0x41cc0f <dlmalloc+351> 0x0041caf0 <+64>: and $0x1,%eax 0x0041caf3 <+67>: xor $0x1,%eax 0x0041caf6 <+70>: lea (%eax,%edx,1),%edx 0x0041caf9 <+73>: mov %edx,%ebx 0x0041cafb <+75>: shl $0x4,%ebx 0x0041cafe <+78>: add $0x527688,%ebx 0x0041cb04 <+84>: mov 0x8(%ebx),%eax 0x0041cb07 <+87>: mov 0x8(%eax),%edi 0x0041cb0a <+90>: cmp %edi,%ebx 0x0041cb0c <+92>: je 0x41d250 <dlmalloc+1952> 0x0041cb12 <+98>: cmp %edi,0x527670 0x0041cb18 <+104>: ja 0x41d561 <dlmalloc+2737> 0x0041cb1e <+110>: mov %edi,0x8(%ebx) => 0x0041cb21 <+113>: mov %ebx,0xc(%edi) 2. Starting program: D:\letodb.exe [New Thread 912.0x864] [New Thread 912.0x96c] warning: Invalid parameter passed to C runtime function. warning: Invalid parameter passed to C runtime function. Падение на Mac-сервер Program received signal EXC_BAD_ACCESS, Could not access memory. Reason: KERN_INVALID_ADDRESS at address: 0x2019825c 0x0001d231 in hb_ip_rfd_set (hSocket=-1) at ../main/src/letodb/common/hbip.c:894 894 FD_SET( hSocket, &rd_fds ); Конкретно в этом случае incoming = hb_ipAccept( hSocketMain, -1, szBuffer, &lTemp ); вернула -1, что является ошибкой

alx_on: Выложил новые изменения Обработка ошибки сети Решение временное, надо по другому как то реализовать Но как затычка пойдет Проверьте у себя внимательно плз Тестировал интенсивно у себя в течении часа. На последнем harbour с SVN! То что раньше падало, максимум, через 20 минут - не упало! Может совпало с погодой? :) PS да, на предмет целостности данных не сильно смотрел, но вроде не должно это повлиять :)

alkresin: Очень интересно! Здорово, что вы на это вышли, Александр. Пожалуй, hb_ipAccept() стоит немного изменить. Получается, что если accept() завершился с ошибкой ( вернул -1 ), но последующий WSAGetLastError() ( или errno для Линукс ) вернул 0, то все вроде-бы в порядке и для этого -1 вызываются другие функции. А ситуация такая может быть, если между вызовами accept() и WSAGetLastError() вклинился другой thread со своими socket вызовами и библиотека сокетов не thread safe.

alkresin: Я поменял немного hb_ipAccept() в свете того, что писал ранее, надеюсь - будет работать.

Pasha: Поправил баг, связанный с установкой кодовой страницы на сервере. По-видимому, он возник после добавления авторизации пользователей: 6-й и более параметры команды intro просто игнорировались

Pasha: Александр, наверное еще в srvleto.h - USERSTRU надо добавить: USHORT uiVarsOwnCurr;

alkresin: Александр, наверное еще в srvleto.h - USERSTRU надо добавить: USHORT uiVarsOwnCurr; Точно, забыл этот файл переписать.

alx_on: Вчера опять падало, 3 раза (сервер вин2008) Все три раза так: (gdb) Starting program: D:\letodb.exe [New Thread 912.0x864] [New Thread 912.0x96c] warning: Invalid parameter passed to C runtime function. warning: Invalid parameter passed to C runtime function. В двух случаях в логах ничего нет, только выходит предупреждение винды На третий в логе странная запись: 06/04/10 15:49:17: Error BASE/1081 Argument error: + Arguments: ( [ 1] = Type: C Val: +6707;0;23;ACCNAME;C;100;0;ACC;C;9;0;CTYPE;N;1;0;GROUP;N;2;0;DOCDEB;C;250;0;DOCKRED;C;250;0;TSALDO;N;1;0;KEYF1;C;6;0;KEYF2;C;6;0;KEYF3;C;6;0;STYPE;N;1;0;INDEPEND;L;1;0;PRICE;N;1;0;ATYPE;L;1;0;KGU;L;1;0;PREDOK;C;12;0;RECCODE;C;12;0;TYPE;L;1;0;KGUDEBET;C;6;0;KGUKREDIT;C;6;0;GRKBK;N;2;0;ACCKF;C;6;0;LDOG;L;1;0;6;accnt;ACCNT;FIELD->ACC;;C;9;accnt;GRP;IF(TYPE,"1","0")+STRZERO( FIELD->GROUP, 2 );;C;3;accnt;GRPACC;IF(TYPE,"1","0")+STRZERO( FIELD->GROUP, 2 ) + FIELD->ACC;;C;12;accnt;SELECT;IF(TYPE,"1","0");;C;1;accnt;PREDOK;FIELD->PREDOK;;C;12;accnt;ACCKF;FIELD->ACCKF;;C;6;, [ 2] = Type: N Val: 0) Похоже только на одно место - server.prg (функция hs_opentable) cReply += leto_rec( nId, nUserStru ) Бред какой то...

Pasha: Александр, а как сделать, чтобы для выполнения функции leto_sum() создавался отдельный поток, и чтобы это работало в обеих харборах ? Выполнение в отдельном потоке может понадобиться и для других потенциально тяжелых операций.

alx_on: На досуге посмотрел почему по времени локально лето и CDX отличаются в 2 раза (не в пользу лето) Половину времени занимает выполнение leto_SendAnswer() Александр, как думаете с чем это связано? Почему так медленно? Все локально, т.е. аппаратная часть не влияет, дрова аналогично Может перейти на асинхронный способ передачи? (плюс непонятные падения сервера - стоит использовать thread safe? Полностью перейти на последний harbour с его MT? Я понимаю, что Вы используете старую версию и вряд ли захотите влезать в проблемы перехода на новую версию, но может стоит попробовать? У данного перехода есть плюс - можно, например, запускать несколько потоков для обслуживания либо разных подключений либо таблиц. Т.е. равномерно распределять открываемые таблицы между потоками при большой загрузке)

Pasha: Добавил для leto_sum возможность суммирования нескольких полей: leto_sum("Sum1,Sum2", cFilter, cScopeTop, cScopeBottom) вернет массив значений {nSum1, nSum2} Если в качестве имеени поля задать символ "#", будет расчитано количество записей в выборке Для одного поля функция, как и раньше, возвращает числове значение - сумму.

alkresin: Александр, а как сделать, чтобы для выполнения функции leto_sum() создавался отдельный поток, и чтобы это работало в обеих харборах ? Полностью перейти на последний harbour с его MT? Реализация дополнительных потоков Harbour-уровня мне не кажется реальной. Для этого потребуется переписывать ядро letodb целиком с тем, чтобы сделать многопоточность на базе Harbour - реализации, а не на тех методах, что используются сейчас. Возможно ли при этом обеспечить совместимость с xHarbour на С уровне - большой вопрос. Я не знакомился с особенностями реализации mt ни в Harbour, ни в xHarbour, но из общих соображений мне это представляется более чем проблематичным. Есть еще одна ( да не одна, наверное :) ) проблема. Я внимательно читал Харборовский мэйллист периода внедрения mt - Przemek особенно подчеркивал, нельзя в параллельных потоках работать с одной таблицей. Если с тех пор ничего не изменилось, то реализация, например, leto_sum() в отдельном потоке возможна лишь при открытии файла в exclusive режиме, что, в общем случае, неприемлемо. Я изначально предполагал для "потенциально тяжелых операций" использовать отдельные процессы, именно поэтому в letodb включен механизм "shared memory", но тут тоже не все просто, я пока не собрался приступить к этому поближе.

alkresin: Вчера опять падало, 3 раза (сервер вин2008) Вот зараза! warning: Invalid parameter passed to C runtime function. Может опять поставить ту проверку в hb_ip_rfd_set() ? Я ее убрал, решив что она уже не нужна ... Похоже только на одно место - server.prg (функция hs_opentable) cReply += leto_rec( nId, nUserStru ) Бред какой то... Думаю, это случайность. Скорее всего, ошибка произошла во время выполнения параллельного потока.

Pasha: alkresin пишет: Есть еще одна ( да не одна, наверное :) ) проблема. Я внимательно читал Харборовский мэйллист периода внедрения mt - Przemek особенно подчеркивал, нельзя в параллельных потоках работать с одной таблицей. Если с тех пор ничего не изменилось, то реализация, например, leto_sum() в отдельном потоке возможна лишь при открытии файла в exclusive режиме, что, в общем случае, неприемлемо. Я тоже учитывал этот момент, когда прокручивал алгоритм "в голове". Такой конфликт можно разрешить блокировкой отдельных таблиц на уровне leto. То есть, пока leto_sum не отработает, другой клиент "висит" на skip по этой же таблице, и наоборот. Это намного лучше, чем сейчас, когда все клиенты ждут, пока не завершится leto_sum.

alkresin: На досуге посмотрел почему по времени локально лето и CDX отличаются в 2 раза (не в пользу лето) Половину времени занимает выполнение leto_SendAnswer() На локальной машине letodb в принципе должно быть медленнее dbfcdx - для выполнения каждой операции сервером выполняются те же методы dbfcdx плюс затраты на прием команды и передачу ответа, а время выполнения tcp/ip приема/передачи ( на сервере + на клиенте ) вполне может быть сравнимо со временем выполнения некоторых RDD методов. Может перейти на асинхронный способ передачи? Я не вижу, как это ускорит реакцию. Сервер и так, когда он не занят выполнением команды, ждет прихода новой и сразу берется за ее исполнение. А на посылку ответа ( leto_SendAnswer() ) это вообще никак не повлияет. Может, стоит поиграть настройками TCP/IP - как в hbip.c, так и на компьютере ...

Pasha: К слову. По сети leto может превосходить dbfcdx по производительности в разы. К примеру, я взял отчет, в котором выполнятся выборка из 3-х таблиц за большой промежуток времени. С dbfcdx он рассчитывался 75 сек, с letodb - 13 сек. Причем никакой отимизации для leto не делал, обьем данных, которые выбираются из таблиц - один к одному. А если еще применить клиент-серверные средства, ограничив обьем данных, передаваемых по сети, разница еще увеличится. Это конечно не общий случай, но все-таки маленький факт.

alx_on: alkresin пишет: нельзя в параллельных потоках работать с одной таблицей. Не знаю как в xHarbour. В Harbour это сделано прозрачно на основе эмуляции XBase++. Передача таблицы между потоками: HB_DBDETACH() и HB_DBREQUEST() Можно без этого - просто распределять открываемые таблицы между потоками, быстрее отклик, лучше отзывчивость, например, в TbBrowse А на посылку ответа ( leto_SendAnswer() ) это вообще никак не повлияет Это повлияет на скорость исполения команд, т.к. поток не будет ждать завершения отсылки ответа, он сразу примется за обработку следующей команды. На локальной машине letodb в принципе должно быть медленнее dbfcdx Локальную машину я привел в пример для исключения влияния железа. Я знаю, что CDX медленнее по сети работает, но у меня есть результаты сравнения с ADS на тех же операциях (она по сети быстрее в 1.5-2 раза) Вообще я не критикую лето, это для меня единственная альтернатива платной ADS Я хочу ее развить (или, по крайней мере приблизить) до уровня ADS

alkresin: Такой конфликт можно разрешить блокировкой отдельных таблиц на уровне leto. То есть, пока leto_sum не отработает, другой клиент "висит" на skip по этой же таблице, и наоборот. Не знаю как в xHarbour. В Harbour это сделано прозрачно на основе эмуляции XBase++. Передача таблицы между потоками: HB_DBDETACH() и HB_DBREQUEST() Можно без этого - просто распределять открываемые таблицы между потоками Да, этот вопрос, наверное, можно решить. Но остается главный - переписать реализацию mt, да так, чтобы обеспечить совместимость Harbour с xHarbour на C уровне. На prg уровне это, наверное, сделать легче, но тогда придется и ядро letodb переводить на prg уровень, что приведет к общему снижению производительности. Я бы предпочел лучше попробовать с процессами.

alkresin: Локальную машину я привел в пример для исключения влияния железа. Я знаю, что CDX медленнее по сети работает, но у меня есть результаты сравнения с ADS на тех же операциях (она по сети быстрее в 1.5-2 раза) Вообще я не критикую лето, это для меня единственная альтернатива платной ADS Да почему бы и не покритиковать ? :) Что касается сравнения с ADS - я делал тесты года два назад, такой разницы не было, результаты были очень близки. В некоторых тестах ( на добавление записи ) letodb был даже заметно быстрее. Надо будет проверить еще раз.

alx_on: alkresin пишет: результаты были очень близки. В некоторых тестах ( на добавление записи ) letodb был даже заметно быстрее В тестах все красиво :) В реальном приложении не очень. Например: частые открытия таблиц очень замедляют работу лето ожидание завершения leto_SendAnswer() тормозит поток обработки команд, что и выливается в такое преимущество ADS. На самом деле поток уже все сделал, только ждет отдачу ответа, хотя мог бы заняться чем то полезным :)

alkresin: частые открытия таблиц очень замедляют работу лето Тут мы вряд ли что-то можем сделать. Хотя... Можно попробовать закрывать таблицы не сразу, а через сколько-то минут, если за истекшее время их никто не откроет опять. ожидание завершения leto_SendAnswer() тормозит поток обработки команд Вы уверены, что hb_ipSend() действительно занимает много времени ? Как вы это проверяли ? Если время выполнения hb_ipSend() настолько критично, можно было бы отдать его другому потоку ( а то и нескольким ) C-уровня.

Pasha: alkresin пишет: Но остается главный - переписать реализацию mt, да так, чтобы обеспечить совместимость Harbour с xHarbour на C уровне. Можно резко упростить задачу, оставив поддержку letodb сервер только для Harbour и обрубив ее для xHarbour. А клиентскую часть оставить и для Harbour, и для xHarbour. Я думаю, для пользователей xHarbour не составит большого труда собрать сервер с помощью Harbour, если станет известно, что сервер под Harbour работает лучше.

alx_on: alkresin пишет: Тут мы вряд ли что-то можем сделать. Хотя... Можно попробовать закрывать таблицы не сразу, а через сколько-то минут, если за истекшее время их никто не откроет опять. Насколько влияет открытие таблицы в PRG от аналогичного на С-уровне? Время запуска VM-машины? Вы уверены, что hb_ipSend() действительно занимает много времени ? Как вы это проверяли ? Замерял время (очень тупо - в начале функции и в конце) Pasha пишет: оставив поддержку letodb сервер только для Harbour Очень хороший вариант!

alkresin: Можно резко упростить задачу, оставив поддержку letodb сервер только для Harbour и обрубив ее для xHarbour. А клиентскую часть оставить и для Harbour, и для xHarbour. В принципе, можно. А в Harbour есть API для mt на C уровне ?

alx_on: alkresin пишет: А в Harbour есть API для mt на C уровне ? Скорее всего есть Судя по наличию hbthread.h должен быть

Andrey: Pasha пишет: Можно резко упростить задачу, оставив поддержку letodb сервер только для Harbour и обрубив ее для xHarbour. А клиентскую часть оставить и для Harbour, и для xHarbour. Я думаю, для пользователей xHarbour не составит большого труда собрать сервер с помощью Harbour, если станет известно, что сервер под Harbour работает лучше. А как тогда добавлять свои функции на хХарборе в СЕРВЕР leto_db ? Переписывать на Харборе ?

Pasha: Andrey пишет: А как тогда добавлять свои функции на хХарборе в СЕРВЕР leto_db ? Переписывать на Харборе ? Так по синтаксису Harbour и xHarbour практически идентичны. Свои функции добавлять надо так же, как и с xHarbour

Andrey: Pasha пишет: Так по синтаксису Harbour и xHarbour практически идентичны. Свои функции добавлять надо так же, как и с xHarbour Так это почти понятно.... Что так сильно различается в лучшую сторону Харбор ? Если будет лучше СЕРВЕР, то смиримся с отсутствием хХарбора. Главное потом чтоб не жалеть, что нет совместимости клиента на хХарборе и сервера на Харборе !

alx_on: alkresin Суммируя вышесказанное Александр, беремся переписать? Со своей стороны предлагаю активное тестирование и помощь в реализации Текущая ситуация похожа на поиск черной кошки в темной комнате. Непредсказуемость поведения библиотек, не расчитанных на MT-режим и невозможность расширения функционала без костылей. А хочется летать! :) Если да, то 1. Переход на Harbour последней версии 2. Возможность запуска нескольких потоков для обработки запросов и(или) обработки таблиц 3. Запуск потоков для встраиваемых функций (plugins? SQL-запросы? Аппетиты растут во время еды...) 4. Асихронная передача сообщений или отдельный поток для этого 5. Корректная обработка падения отдельного потока, не затрагивающая остальные потоки и (или) клиентские соединения (ну это уже так, мечты) 6. И т.д. и т.п.

alkresin: Суммируя вышесказанное Александр, беремся переписать? Со своей стороны предлагаю активное тестирование и помощь в реализации Только не так резво :). Для начала надо как следует разобраться с моделью mt в Harbour, с возможностью ее использования на С уровне, с тем, какие ограничения она наложит на возможную реализацию. После беглого просмотра некоторых материалов меня особенно напрягло вот это: Workareas are fully thread separated. Each threads uses it's own workareas so there is not need to synchronize access to WA. The same if for SETs (so _SET_DELETED, and similar switches are local to thread and does not effect other threads) and some RDD attributes like default RDD driver, current WA, neterr flag, etc. Each thread has it's own table for ALIASes and aliases are not shared between threads. Just like memvars. Only RDD nodes and RDD settings (rddInfo()) are global to application. > Are there public wa for all MT and private wa for one MT? private for MT. > Will it be possible to close all private wa of a single MT? dbCloseAll() - it closes all workareas open by thread which executes it. When you terminate thread then all open by this thread WA are closed automatically. И учтите, что реализация mt приложений достаточно сложна, и при переходе к Harbour модели нам наверняка встретится еще не одна "черная кошка в темной комнате" :). Так что я предпочел бы продолжить искать свою кошку параллельно с исследованием Harbour mt ( полностью согласен, что его использование, если удастся успешно обойти/учесть его ограничения, очень заманчиво ).

alx_on: alkresin пишет: особенно напрягло Ничего плохого не вижу. Если, например, будем переделывать REALTIONS в сторону выполнения на сервере, тогда да, есть сложные моменты, связанные с передачей в поток сразу нескольких таблиц. На текущей реализации никаких ограничений я не увидел. Каждый поток будет обрабатывать свой набор таблиц. Или будет запрашивать (если это не сильно накладно по времени) у главного держателя таблиц. Так что я предпочел бы продолжить искать свою кошку параллельно с исследованием Harbour mt Развивать поиск кошек на данный момент некуда. На вин и маке падают по разному и отловить можно только случайно ценой потери минимум дня тестов. Я считаю, что мы уже уперлись в ограничения. Давайте выделим отдельную ветку для перехода. Старую можно использовать для работы и косметических доработок, на новой версии обкатывать MT

Pasha: alkresin пишет: Workareas are fully thread separated. Я не копался в Harbour mt, а надо бы :) Из прочитанного можно понять, что надо для каждого потока создавать отдельную WA для одной и той же таблицы. А ведь в leto WA для таблицы, открываемой несколькими пользователями, одна. А при создании потока уже открытые WA ему доступны ? Конечно, надо решить несколько таких принциальных моментов. Например (это пока только для обсуждения), можно создавать отдельную WA для каждой команды USE, поступающей с клиента. Харбор в этом случае (как ни удивительно) работать будет. Но тогда таблицы прийдется открывать в shared-режиме, что нежелательно. Да и надо продумать, что в этом случае будет, к примеру, с транзакциями. Хоты в leto они выполняются на клиента. Может быть еще есть какие-то мели и подводные камни. Или оставить существующую схему работы с WA, но тогда прийдется блокировать таблицы для разрешения конфликта с разными потоками. PS Я к вам конечно присоединюсь :)

Andrey: alx_on пишет: Давайте выделим отдельную ветку для перехода. Старую можно использовать для работы и косметических доработок, на новой версии обкатывать MT Давайте не так быстро... Может после изучения и проработки на бумаге технологии перехода ?

alkresin: Каждый поток будет обрабатывать свой набор таблиц А как быть с транзакциями ? Или будет запрашивать (если это не сильно накладно по времени) у главного держателя таблиц. Вот именно - если это не сильно накладно по времени. Т.е. главный поток будет анализировать команды; если это открытие таблицы, то проверит, открыта ли она уже для других клиентов и, если нет, вызывает специальный поток - держатель таблиц для ее открытия, а если да - то другой поток для ее DBREQUEST и т.п. ... Я это все к тому, что архитектура требует тщательнейшего продумывания на предмет согласованности работы потоков и достижения приемлемой производительности. Развивать поиск кошек на данный момент некуда. На вин и маке падают по разному и отловить можно только случайно ценой потери минимум дня тестов. Я считаю, что мы уже уперлись в ограничения. Есть еще варианты и появятся другие. Первое, что я попробую - это сделать c iprecv то же, что сделали с ipaccept, - проверять не только по hb_iperrorcode(), но и по возвращаемому функцией значению. Если бы вы все-таки попробовали перекомпилировать сервер на старой версии Harbour и потестировали бы его, это было бы существенное продвижение - было бы яснее, куда смотреть. У меня-то все сейчас работает ( даже без последних корректировок ) - 14-ый день без проблем... Давайте выделим отдельную ветку для перехода. Ветку CVS ? Я бы предпочел просто создать новый каталог - так мне кажется проще и удобнее. В этих средствах CVS, связанных с ветвлением, я не очень ориентируюсь и боюсь запутаться.

alkresin: А при создании потока уже открытые WA ему доступны ? Насколько я понял - нет. Например (это пока только для обсуждения), можно создавать отдельную WA для каждой команды USE, поступающей с клиента. Харбор в этом случае (как ни удивительно) работать будет. Но тогда таблицы прийдется открывать в shared-режиме, что нежелательно. А в letodb и сейчас есть такой режим работы - NO_SAVE_WA = 1 в letodb.ini, я, правда, его толком не тестировал, поэтому и в readme не упомянул, только в Changelog. Да и надо продумать, что в этом случае будет, к примеру, с транзакциями. Мда... Это особенная тема. Сейчас одно из главных свойств транзакций ( целостность, что ли - забыл уже, как называется ) гарантируется именно тем, что все они выполняются в одном потоке, т.е. строго одна за другой. Может быть еще есть какие-то мели и подводные камни. :):) Я, помню, немало помучился, прежде чем нормально заработала нынешняя mt схема - то производительность резко падала, то вообще глухо все висло.

alx_on: Pasha пишет: Но тогда таблицы прийдется открывать в shared-режиме, что нежелательно Если использовать один или оба варианта 1. Для каждого потока свой набор таблиц. Т.е. какая то определенная таблица будет использоваться всеми пользователями (открывается лето в exclusive-режиме) и только этот поток ее обрабатывает. 2. Между потоками передаем таблицу (например, для leto_sum в отдельном потоке) с помощью стандартных функций харбора то проблемы, как таковой, вообще не существует! (скорость передачи таблицы окупится общей скоростью выполнения и общим увеличением отзывчивости сервера) Для транзакций на стороне сервера нужно будет придумать хорошее решение, но! Главное начать, а там само пойдет :) В текущем варианте транзакций даже менять ничего не надо для клиента. Для сервера можно запускать поток, который будет выступать в роли клиента для остальных потоков с таблицами (т.е. он последовательно отдает команды на обновление таблиц, раскиданных по потокам)

alkresin: Для транзакций на стороне сервера нужно будет придумать хорошее решение, но! Главное начать, а там само пойдет :) Вы эти горбачевские штучки бросьте :). Он вот так именно и говорил - и как оно "пошло" и к чему пришло мы все свидетели. Впрочем, это тема для другого форума... Начать можно, я не против. Просто надо сначала поизучать, как организовывать mt в Harbour на С уровне. Я этого еще не знаю.

alkresin: Кстати, нет ли у кого в загашнике теста производительности RDD, а то я свои растерял ? Написать-то недолго, конечно, но ...

КСС: Всем привет. Помнится, в молодости, когда я работал в КБ на военном радиозаводе и разрабатывал кой-какую аппаратуру, бывало на полпути понимал, что сама идея имеет недостатки, которые не позволят реализовать все задачи. Тогда я шёл к руководителю проекта и предлагал новые решения и убедительно доказывал, что прежняя никуда не годится. Его ответ я запомнил и руководствуюсь всю жизнь. Он сказал: "Лучшее - враг хорошего. Сделай хорошее, а потом займёшься лучшим". Кстати, в производство пошёл именно "хороший" вариант, а до лучшего руки так и не дошли. Предлагаю довести до совершенства и максимально возможной стабильности существующий вариант, а затем спокойно делать что-то новое на старых ошибках. Если, к тому времени, кому то это ещё будет нужно.

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

Pasha: Александр, посмотрите пожалуйста такой случай Перед транзакцией запись удалена Делаем: leto_BeginTransaction() ... dbRecall() ... leto_CommitTransaction() ? Deleted() // true, т.е. запись остается удаленной, хотя фактически recall сработал. Если сделать skip -1 skip 1 ? Deleted() то возвращается false

alkresin: Сделал небольшой тест для сравнения скорости RDD ( слова Александра о превосходстве ADS меня задели, тем более, что и для меня ADS с самого начала был ориентиром ): #define KOL_ITER 10000 FUNCTION Main( cPathLeto ) PRIVATE cPathAds := "//199.10.11.5:6262/data/" PRIVATE cTable := "test.dbf" PRIVATE aDbf := { { "F1","C",20,0 }, { "F2","L",1,0 }, { "F3","N",12,2 }, ; { "F4","N",8,0 }, { "F5","C",30,0 } } IF Empty( cPathLeto ) cPathLeto := "//199.10.11.5:2814/" ELSE cPathLeto := "//" + cPathLeto ENDIF SET( _SET_FILECASE, 1 ) SET( _SET_DIRCASE, 1 ) SET PRINT ON SET PRINTER TO test_speed.txt ADDITIVE #ifdef RDD_ADS #include "ads.ch" rddSetDefault( "ADS" ) SET FILETYPE TO CDX adsSetServerType( 6 ) adsrightscheck( .F. ) SET AXS LOCKING ON Test( cPathAds ) #endif #ifdef RDD_LETO REQUEST LETO Rddsetdefault( "LETO" ) Test( cPathLeto ) #endif RETURN Nil FUNCTION TEST( cPath ) LOCAL i, n, nSec, sFilter ? "Start", cPath, "iterations: "+Ltrim(Str(KOL_ITER)) ? "---------------------------------------" dbCreate( cPath + cTable, aDbf ) USE ( cPath + cTable ) NEW SHARED nSec := Seconds() FOR i := 1 TO KOL_ITER dbAppend() REPLACE F1 WITH "Test" + Str(i,10), ; F2 WITH ( i%2 == 1 ), ; F3 WITH Seconds(), ; F4 WITH ( KOL_ITER - i ) % 758 + ; Iif( i%3 == 0, 400, Iif( i%3 == 1, 200, 600 ) ), ; F5 WITH Replicate( "m",25 ) NEXT ? "Append", Seconds()-nSec nSec := Seconds() INDEX ON Str(F3+F4,12,2) TAG T1 INDEX ON Str(F4,8)+F1 TAG T2 ? "Indexing", Seconds()-nSec ordSetFocus( "T1" ) nSec := Seconds() GO TOP DO WHILE !Eof() n := F4 dbSkip(1) ENDDO ? "Skipping Forward (I)", Seconds()-nSec nSec := Seconds() DO WHILE !Bof() n := F4 dbSkip(-1) ENDDO ? "Skipping Back (I)", Seconds()-nSec SET ORDER TO 0 nSec := Seconds() GO TOP DO WHILE !Eof() n := F4 dbSkip(1) ENDDO ? "Skipping Forward", Seconds()-nSec nSec := Seconds() DO WHILE !Bof() n := F4 dbSkip(-1) ENDDO ? "Skipping Back", Seconds()-nSec nSec := Seconds() FOR i := 1 TO 30 sFilter := "F4 < " + Ltrim( Str( i * 15 ) ) SET FILTER TO &sFilter GO TOP DO WHILE !Eof() n := F4 dbSkip(1) ENDDO NEXT ? "Filtering-1", Seconds()-nSec nSec := Seconds() FOR i := 1 TO 50 GO TOP DO WHILE !Eof() n := F4 dbSkip(1) ENDDO NEXT ? "Filtering-2", Seconds()-nSec SET FILTER TO nSec := Seconds() FOR i := 1 TO KOL_ITER GO i n := F4 NEXT ? "Go to record", Seconds()-nSec ordSetFocus( "T2" ) nSec := Seconds() FOR i := 1 TO KOL_ITER GO i sFilter := Str(F4,8)+F1 GO TOP SEEK sFilter NEXT ? "Seeking", Seconds()-nSec ? ? CLOSE ALL RETURN Nil Серевер - ASPLinux 11.2, CPU Pentium 4, 3000GHz, ОЗУ 2Gb Вот результаты: Start //199.10.11.5:6262/data/ iterations: 10000 --------------------------------------- Append 7.00 Indexing 0.22 Skipping Forward (I) 0.66 Skipping Back (I) 0.64 Skipping Forward 0.52 Skipping Back 0.52 Filtering-1 2.06 Filtering-2 3.98 Go to record 2.36 Seeking 7.72 Start //199.10.11.5:2814/ iterations: 10000 --------------------------------------- Append 4.59 Indexing 0.16 Skipping Forward (I) 0.55 Skipping Back (I) 0.58 Skipping Forward 0.52 Skipping Back 0.51 Filtering-1 2.95 Filtering-2 7.38 Go to record 2.39 Seeking 9.11 Запустил еще раз: Start //199.10.11.5:6262/data/ iterations: 10000 --------------------------------------- Append 7.25 Indexing 0.22 Skipping Forward (I) 0.66 Skipping Back (I) 0.64 Skipping Forward 0.52 Skipping Back 0.53 Filtering-1 2.09 Filtering-2 4.00 Go to record 2.39 Seeking 7.69 Start //199.10.11.5:2814/ iterations: 10000 --------------------------------------- Append 4.61 Indexing 0.16 Skipping Forward (I) 0.58 Skipping Back (I) 0.59 Skipping Forward 0.56 Skipping Back 0.56 Filtering-1 3.05 Filtering-2 7.09 Go to record 2.38 Seeking 7.64 Цифры для двух запусков чуть отличаются - сервер-то рабочий, загрузка меняется - но основные соотношения между Ads и Leto остаются. По результатам тестов Leto заметно быстрее добавляет записи и индексирует ( быстрая индексация - целиком заслуга dbfcdx ), немного быстрее ( процентов на 15 ) ходит по индексированной базе и практически так же, как ADS - по неиндексированной; примерно одинаковые результаты по go to и seek. Ads заметно быстрее фильтрует - по-видимому, за счет того, что его встроенный движок интерпретации выражений гораздо проще и, соответственно, быстрее, чем у Harbour.

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

alx_on: alkresin пишет: Сделал небольшой тест для сравнения скорости RDD ( слова Александра о превосходстве ADS меня задели, тем более, что и для меня ADS с самого начала был ориентиром ) Никого не хотел задеть или каким либо образом обидеть. Как я уже говорил у меня тоже на тестах все отлично. Потому то я и выбрал лето :) На реальном приложении с реальной базой не все так радужно Конечно, можно сказать про проблемы реализации самого приложения, но факт остается фактом - ADS считала быстрее (я потом смог переделкой прилаги достичь скорости ADS до переделки, но и скорость ADS тоже выросла)

alkresin: Я считаю, что комфортность работы (скорость и отзывчивость системы, надежность) является для данного типа продуктов главным приоритетом. И лишь бы работало (хоть иногда) - это не ответ. Согласен. Но как раз "комфортность" работы здесь и сейчас, с моими клиентскими приложениями - в полном порядке. И работает оно не "хоть иногда", а, как и положено, 24 часа в сутки, стабильно и надежно. Я это к тому, что не все так плохо :). Поэкспериментировать с реализацией ядра я не отказываюсь. Никого не хотел задеть или каким либо образом обидеть. Да не обиделся я, Александр, мне уже давно не 20 лет :). "Задели" ваши слова по-хорошему - лень объяснять, надеюсь поймете. Я верю, что в вашем конкретном случае ADS заметно быстрее. Это может быть вызвано или какими-то особенностями ОС, сетевой среды ( с этой точки зрения было бы неплохо, если б вы повторили мой тест у себя ), или тем, что в ваших приложениях наиболее активно используются как раз те операции, где ADS реально быстрее. По результатам моих тестов это фильтрация. Особенно заметна разница при повторных проходах по отфильтрованной базе. По-видимому, ADS использует какие-то механизмы оптимизации, запоминает в буфере номера записей, попадающих в фильтр. В своих клиентских приложениях я это делаю при необходимости сам.

alkresin: Pasha пишет: Перед транзакцией запись удалена ... Посмотрю. Где-то в буфере на клиентской стороне остается этот флаг.

Andrey: Случайно нашел: Откуда взял http://forum.ru-board.com/topic.cgi?forum=8&topic=34526&start=20 DBF рулит....

alkresin: Pasha пишет: Александр, посмотрите пожалуйста такой случай Перед транзакцией запись удалена Сделал такой тест: Function Main Local cPath := "//127.0.0.1:2812/" REQUEST LETO RDDSETDEFAULT( "LETO" ) ? "Start" dbCreate( cPath+"Nakl1", { {"NORD","N",10,0} } ) use ( cPath+"Nakl1" ) New append blank replace nord with 10 append blank replace nord with 20 unlock go top delete ? "Deleted ?", deleted() skip(1) go top ? "Deleted ?", deleted() leto_BeginTransaction() dbRecall() leto_CommitTransaction() ? "Deleted ?", deleted() ? Return Nil Результат: Deleted ? .T. Deleted ? .T. Deleted ? .F. Вроде, все правильно работает ...

Pasha: Значит, есть еще какой-то фактор, вилияющий на этот флажок У меня этот глюк проявляется в большой транзакции. Я покопаюсь еще и попробую выяснить, в чем дело

alkresin: Pasha, мне кажется, вы что-то не так сделали при последних исправлениях в реализации leto_intro - портится формат даты. Теперь, если во время сеанса работы открывались таблицы ( при этом вызывается setuserenv ), во всех последующих записях в журнал, в т.ч. при остановке сервера, вместо даты пишется ;F. Это ведь и на выполнение операций, связанных с датой, может влиять.

alkresin: Я разделил letofunc.c на 2 файла - выделил в letocore.c ядро, те функции, которые организуют работу сервера. Предлагаю построить работу по созданию нового ядра следующим образом: 1. Создать новый файл ( cernel2.c, например ), где будет реализована та же схема использования потоков, что и сейчас, только методами Harbour mt. В любом случае у нас будет поток, принимающий соединения и, как минимум один, поток, исполняющий RDD операции, так что это будет нормальная база для дальнейшей работы. 2. Отлаживаем - чтоб работало стабильно и с не меньшей производительностью, чем действующий вариант, без этого дальше идти нет смысла. 3. Прорабатываем и реализуем схему взаимодействия дополнительных потоков.

Pasha: alkresin пишет: Pasha, мне кажется, вы что-то не так сделали при последних исправлениях в реализации leto_intro - портится формат даты. Теперь, если во время сеанса работы открывались таблицы ( при этом вызывается setuserenv ), во всех последующих записях в журнал, в т.ч. при остановке сервера, вместо даты пишется ;F. Это ведь и на выполнение операций, связанных с датой, может влиять. Дело оказалось не в последних исправлениях Раньше этот код: [pre] if( nParam > 5 ) { if( ( ptr = strchr( pp1, ';' ) ) != NULL ) { *ptr = '\0'; pUStru->cdpage = hb_cdpFind( pp1 ); pp1 = ptr + 1; if( ( ptr = strchr( pp1, ';' ) ) != NULL ) { if( pUStru->szDateFormat ) hb_xfree( pUStru->szDateFormat ); pUStru->szDateFormat = (char*) hb_xgrab( ptr - pp1 + 1 ); memcpy( pUStru->szDateFormat, ptr, ptr - pp1 ); pUStru->szDateFormat[ptr-pp1] = '\0'; if( *(ptr + 1) == ';') pUStru->bCentury = (*(ptr + 2) == 'T' ? TRUE : FALSE); } } }[/pre] игнорировался, а теперь он отрабатывается. А в нем ошибка: вместо memcpy( pUStru->szDateFormat, ptr, ptr - pp1 ); надо memcpy( pUStru->szDateFormat, pp1, ptr - pp1 ); Действительно серьезная ошибка, приведет к тому, что DTOC() в фильтрах и индексах на сервере не будет работать Я смогу исправить на CVS только вечером, так что есть есть возможность - поправьте

Pasha: Кстати, а как закрывается letodb при выключении сервера (windows) ? Я смотрю, в логе нет записи про останов сервера

alkresin: Я смогу исправить на CVS только вечером, так что есть есть возможность - поправьте Спасибо за информацию. Поправлю. Кстати, а как закрывается letodb при выключении сервера (windows) ? Боюсь, что никак. Я его использую под Линуксом и там у меня прописан стандартный скрипт для запуска/остановки служб. А под Windows надо, наверное, обработку сигнала соответствующего сделать.

Pasha: Александр, помогите пожалуйста исправить ошибку, связанную с relations: Сэлф-контайнед такой: Local nId dbCreate("Table1", {{'id', 'N', 8, 0}}) dbCreate("Table2", {{'id', 'N', 8, 0},{'Name','C',20,0}}) USE table1 new shared INDEX ON id TAG table1 USE table2 new shared INDEX ON id TAG table2 for nId := 1 to 100 table1->(dbAppend()) table1->Id := nId table2->(dbAppend()) table2->Id := nId next table1->(dbCommit(), dbUnlock()) table2->(dbCommit(), dbUnlock()) select table1 dbSetRelation( "table2", {|| id}, "id" ) seek 2 //Если снять комментарий со следующего оператора (чтение любого поля table2), ошибка исчезает //? table2->Id if table2->(RLock()) table2->Name := '1' ? table2->(dbRecordInfo(2)) // .T. // запись как будто блокирована, но table2->(dbCommit()) // ошибка endif На клиенте flush выдает команду "upd", и ошибка возникает на сервере в UpdateRec: if( ( !pTA || ulRecNo ) && pAStru->pTStru->bShared && !pAStru->bLocked && leto_IsRecLocked( pAStru, ulRecNo ) != 1 ) { /* The table is opened in shared mode, but the record isn't locked */ if( !pTA ) hb_xvmSeqEnd(); return 4; }

Pasha: alkresin пишет: цитата: Кстати, а как закрывается letodb при выключении сервера (windows) ? Боюсь, что никак. Я его использую под Линуксом и там у меня прописан стандартный скрипт для запуска/остановки служб. А под Windows надо, наверное, обработку сигнала соответствующего сделать. В xHarbour наверное можно воспользоваться функцией: HB_PushSignalHandler( HB_SIGNAL_QUIT, "Handle" ) ... Function Handle( nSignal, aParams ) IF nSignal == HB_SIGNAL_QUIT ... а какой аналог есть в Harbour ? Эту обработку делать только для windows ?

alkresin: Александр, помогите пожалуйста исправить ошибку, связанную с relations: Исправил. Там при блокировке запись в дочерней area не устанавливалась предварительно в соответствие с родительской. Кстати, такая же ерунда может и при replace для этой записи произойти. а какой аналог есть в Harbour ? Эту обработку делать только для windows ? 1)Не знаю, не смотрел 2)По-хорошему, и для Линукс надо - не все ведь правильно letodb установят.

Pasha: alkresin пишет: Исправил. Спасибо

Pasha: Наверное, надо бы переделать генерацию ошибок на клиенте, и соответственно передачу полной информации об ошибке с сервера А то сейчас вместо lock required получаем data type error. Делаем ?

alkresin: Наверное, надо бы переделать генерацию ошибок на клиенте, и соответственно передачу полной информации об ошибке с сервера Да, конечно, дело нужное.

Andrey: Pasha пишет: Кстати, а как закрывается letodb при выключении сервера (windows) ? Я смотрю, в логе нет записи про останов сервера alkresin пишет: А под Windows надо, наверное, обработку сигнала соответствующего сделать. Вот, вот я об этом в самом начале писал ! Сидит процесс в Windows'e и только ручками можно удалить. Не по правилам сделано. Нужно наверно как у всех в трее сделать, чтоб останавливать можно было ! А для терминала, тоже запрос нужно делать, а не по ESC - чтоб отключался....

alkresin: Вот, вот я об этом в самом начале писал ! Сидит процесс в Windows'e и только ручками можно удалить. Не по правилам сделано. Нужно наверно как у всех в трее сделать, чтоб останавливать можно было ! В трэй его можно посадить только средствами одной из GUI оболочек. Вы хотите, чтобы я всех принудительно посадил на HwGUI ? Если нужна такая штука, напишите маленькую GUI утилиту теми инструментами, которые вы используете ( HwGUI, MiniGui, Fivewin, ... ) - чтобы она запускала и останавливала сервер ( letodb, letodb stop ). Еще одно преимущество такого решения - сам сервер избавлен от необходимости обрабатывать сообщения, идущие на его окно и занимается исключительно своими непосредственными задачами. А для терминала, тоже запрос нужно делать, а не по ESC - чтоб отключался.... Вы имеете ввиду сервер, скомпилированный с __CONCOLE__ ? Это ж экспериментальный режим, использовавшийся только на начальной стадии разработки. Забудьте про него.

alx_on: alkresin пишет: Предлагаю построить работу по созданию нового ядра следующим образом Поддерживаю PS я не потерялся, просто офис переезжает (и я вместе с ним :) ) в выходные включусь в обсуждения и доработку

Andrey: alkresin пишет: Еще одно преимущество такого решения - сам сервер избавлен от необходимости обрабатывать сообщения, идущие на его окно и занимается исключительно своими непосредственными задачами. Спасибо, понял.

Pasha: alkresin пишет: Если нужна такая штука, напишите маленькую GUI утилиту теми инструментами, которые вы используете ( HwGUI, MiniGui, Fivewin, ... ) - чтобы она запускала и останавливала сервер ( letodb, letodb stop ). Можно сделать такую утилитку средствами hwgui, и положить ее в letodb\utils В связи с этим обьявляется конкурс на иконку для letodb-tray

Pasha: Pasha пишет: Значит, есть еще какой-то фактор, вилияющий на этот флажок У меня этот глюк проявляется в большой транзакции. Я покопаюсь еще и попробую выяснить, в чем дело Докладываю. Вот в таком случае: Local nId dbCreate("Table1", {{'id', 'N', 8, 0}}) use table1 shared for nId := 1 to 10 table1->(dbAppend()) table1->Id := nId next go top if RLock() leto_BeginTransaction() dbDelete() skip skip -1 dbCommit() leto_CommitTransaction() dbUnlock() endif ? RecNo(), Deleted() // .F. skip skip -1 ? RecNo(), Deleted() // .T. флажок deleted() возвращается неправильный

AlexMyr: Привет. у меня такой результат 1 .F. немного поспешил .T. 1 .T.

Andrey: Pasha пишет: В связи с этим обьявляется конкурс на иконку для letodb-tray Первое приближение:

PSP:

alx_on: Может сервисом все таки сделать? Удобнее во всех отношениях и не надо на сервере логиниться для запуска

Andrey: alx_on пишет: Может сервисом все таки сделать? Нет нужен выбор, как у всех продуктов: 1) Приложение (Application) 2) Сервис (Service) Но я тоже за СЕРВИС, мне его удобней использовать под Виндой !

alkresin: Pasha пишет: Докладываю. Вот в таком случае: ... флажок deleted() возвращается неправильный Ясно. Такая же история будет, если вы поле какое-то замените, т.е. вместо dbDelete() - table1->Id := 100, а потом ? Recno(), table1->Id . Дело в том, что запись фактически изменяется только в момент вызова leto_CommitTransaction() и skip, skip -1 во время транзакции приводят к тому, что в буфер записываются необновленные значения. Надо будет в leto_CommitTransaction() поставить автоочищение буферов.

alkresin: Надо будет в leto_CommitTransaction() поставить автоочищение буферов. Не так оно просто ... Может, лучше не надо во время транзакции возвращаться на измененную во время этой транзакции запись ? Честно говоря, не вижу в этом действии никакого смысла. Повторно что-то в ней изменить ? А почему тогда сразу не сделать необходимые изменения ? Транзакция - это все таки процедура специфическая, она предназначена исключительно для изменения/добавления данных и другие действия в ней не должны иметь места. Кстати, dbCommit() в транзакции не нужен - он просто не исполняется.

Pasha: Я вижу 2 выхода: 1) простой. После CommitTransaction выдавать запрос на чтение в изменившихся WA, т.е. goto(recno()) Но при этом во время транзакции содержимое записей может быть искаженным, т.е. до изменения, что тоже нежелательно. 2) во время транзакции после получения ответа с сервера в операциях навигации просматривать буфер транзакции, и, если запись, полученная с сервера, есть в буфере, заменять ее значение данными из буфера.

Pasha: alx_on пишет: Может сервисом все таки сделать? В Harbour эта возможность появилась всего месяц назад. Кто нибудь тестировал contrib\hbwin\win_svc.c ? Годится для letodb ?

Петр: Pasha пишет: Кто нибудь тестировал contrib\hbwin\win_svc.c Не работает в MT и не только. Т.е. сервис инсталируется/деинсталируется, но не запускается. По крайней мере у меня . Вот еще любопытная цитата I'm not familiar with services in MS-Windows so I hope that real MS-Windows programmers can verify the text below. MSDN says that StartServiceCtrlDispatcher() makes calling thread service dispatcher which creates new thread to execute the appropriate ServiceMain function when a new service is started. It means that current win_svc.c code cannot work with MT HVM because it does not initialize new HVM stack for newly created thread. It also does not unlock HVM stack used by thread calling StartServiceCtrlDispatcher() what will cause deadlock when some other thread activates GC. It works with ST HVM because thread created for ServiceMain function reuses the HVM stack bound with thread calling StartServiceCtrlDispatcher() taking its address from static variable. It does not work with MT HVM because in MT mode each HVM thread extracts HVM stack pointer from TLS so newly create thread takes NULL as its own stack pointer. If you want to use this code with MT HVM then it has to be adopted to work safely with it. It should create and destroy on exit new HVM stack and encapsulate call to StartServiceCtrlDispatcher() into hb_vmUnlock()/ hb_vmLock(). best regards, Przemek

alkresin: 1) простой. После CommitTransaction выдавать запрос на чтение в изменившихся WA, т.е. goto(recno()) Не хотелось бы - это приведет к заметному снижению производительности, причем для большинства случаев неоправданному. Я уже думал об этом, надо тогда добавлять флаг в area и определенную логику в leto_getValue() и пр., чтобы перечитывать запись только когда это действительно нужно. ) во время транзакции после получения ответа с сервера в операциях навигации просматривать буфер транзакции, и, если запись, полученная с сервера, есть в буфере, заменять ее значение данными из буфера. В общем случае это невозможно, т.к. записи может и не быть в буфере, поэтому это не может быть решением. Я все же не вижу ни одной причины, зачем было бы нужно возвращаться к записи во время транзакции ...

Pasha: alkresin пишет: В общем случае это невозможно, т.к. записи может и не быть в буфере, поэтому это не может быть решением. Почему невозможно ? В буфере транзакций хранятся только изменившиеся записи. Если прочитанной записи в буфере нет, значит оставляем ее такой, какая она пришла с сервера, а если есть - изменяем. Меня сейчас интересует не сложность реализации, а принципиальная правильность подхода. Да и на быстродействие это повлияет незначительно, так как от сервера ничего получать не надо, надо только выполнить поиск в буфере транзакции. А поиск этот лучше сделать в leto_ParseRec. Я все же не вижу ни одной причины, зачем было бы нужно возвращаться к записи во время транзакции ... Скажем, есть основной документ и связанные с ним. Во время транзакции изменяется основной документ, затем связанные, и затем указатель возвращается к основному. А он оказывается таким, каким был до изменения. Вот я как раз нарвался на такую ситуацию. Да мало ли, какие случаи еще могут встретиться.

alkresin: Почему невозможно ? В буфере транзакций хранятся только изменившиеся записи. Если прочитанной записи в буфере нет, значит оставляем ее такой, какая она пришла с сервера, а если есть - изменяем. Из буфера транзакции - да, согласен, можно. Скажем, есть основной документ и связанные с ним. Во время транзакции изменяется основной документ, затем связанные, и затем указатель возвращается к основному. Так зачем возвращать указатель на основную во время транзакции ? Почему не после ? Да мало ли, какие случаи еще могут встретиться. Нет таких случаев, чтобы необходимо было делать это именно во время транзакции.

Pasha: alkresin пишет: Нет таких случаев, чтобы необходимо было делать это именно во время транзакции. Да есть. Предположим, я решил оформить расчет зарплаты 1-го работника как транзакцию. Упрощаю. Есть таблица удержаний. Считаю налоги (у нас их 4 штуки). Затем считаю алименты, для чего суммирую уже рассчитанные налоги, чтобы отнять их от дохода и... не нахожу их, так как на сервере их еще нет. Затем считаю перечисление на сберкнижку, для чего нужны все выше перечисленное, и... опять его нет ! Затем... там много видов удержаний еще есть. Про начисления я и не заикаюсь, там еще более сложные случаи

AlexMyr: Pasha пишет: Упрощаю. Есть таблица удержаний. Считаю налоги (у нас их 4 штуки). Затем считаю алименты, для чего суммирую уже рассчитанные налоги, чтобы отнять их от дохода и... не нахожу их, так как на сервере их еще нет. А зачем их искать на сервере если они рассчитаны и они либо в массиве либо во временной таблице или в памяти? Взял исходные данные с сервера, рассчитал все что нужно и положил на сервер результат.

Pasha: Насколько я помню, функции hs_* в server.prg не стали переписывать на C из-за обработчика ошибок на C-уровне Достаточно ли использование последовательности hb_xvmSeqBegin(); ... hb_xvmSeqEnd(); для обработки ошибок ? Если да, то может стоит переписать оставшиеся функции на C ?

Pasha: Обнаружил и исправил еще один глючек с блокировками. Вызов: goto 1 dbrlock(1) goto 2 dbrlock(2) работает а если сделать так: dbrlock(1) dbrlock(2) то фактически блокируется только текущая запись. Исправления выложу вечером

Pasha: AlexMyr пишет: А зачем их искать на сервере если они рассчитаны и они либо в массиве либо во временной таблице или в памяти? Они рассчитаны, но не хранятся ни в массиве, ни во временной таблице. Конечно, теоретически можно переделать таким образом алгоритм. Но я этого делать не стану. Алгоритм сложный и громоздкий, там более 80к кода, я его дал в очень упрощенном виде. Скажем, один налог зависит от остальных трех, налоги за каждый месяц пересчитыватся отдельно, и глубина перерасчета не ограничена. Бывали ситуации, когда делали доплаты и пересчитывали налоги за 2 года, т.е. за 24 месяца. При перерасчетах надо учитывать все перарасчеты за все месяца, а также все изменения мин.зарплаты (аналог МРОТ) за все периоды, а они у нас меняются несколько раз в год, растут (правительство нас очень любит и заботится). Я уж лучше от транзакции откажусь. Или поправлю тразакцию, тем более как это делать - понятно. А пример я могу дать еще. Скажем, проводится накладная. На ее основе формируется налоговая накладная, это у нас аналог счет-фактуры (которая может не совпадать с накладной). Затем надо вернуться в накладную, и записать в нее данные налоговой накладной. Так что в общем это беспредметный разговор. Жизнь сама даст примеры

AlexMyr: Pasha Тоже приходиться пересчитывать но максимум это 2-3 месяца (по больничным). А так все рассчитал, результат в массив, и в конце из массива в базу. Если не секрет что за доплата такая, что нужно за 2 года пересчет делать? P.S. Я из Украины, в профиле уже указал.

Pasha: AlexMyr пишет: Тоже приходиться пересчитывать но максимум это 2-3 месяца (по больничным). А так все рассчитал, результат в массив, и в конце из массива в базу. Если не секрет что за доплата такая, что нужно за 2 года пересчет делать? P.S. Я из Украины, в профиле уже указал. Да то ли выслугу неправильно считали, то ли ранг. Через 2 года это обнаружили, и пересчитывали за весь период. Я знаю Алексей, что вы с Украины, по leto mail list. Просто я стараюсь писать, чтобы и остальным было понятно, о чем речь

alkresin: Да есть. Предположим, я решил оформить расчет зарплаты 1-го работника как транзакцию. Вот именно тут я с вами несогласен. По моему глубокому убеждению, транзакция предназначена исключительно для записи данных, все остальное - до и после нее. Я понимаю, что удобно просто выделить кусок кода, ничего в нем не меняя, поставить в начале и в конце begintransaction/endtransaction - и все. Но это, вообще говоря, порочный подход. Впрочем, в самой по себе корректировке из буфера, которую вы предлагаете, ничего плохого нет. Другое дело, что я не рекомендовал бы использовать транзакции так, чтобы она могла понадобиться :).

alkresin: может стоит переписать оставшиеся функции на C ? Стоит. И надо избавиться от класса HApp и, соответственно, PUBLIC oApp. Я тут переписал mt на Harbour модель и у меня теперь при вызове этих функций сервер падает, т.к. второй поток не знает переменной oApp. Т.е. надо или при создании нового потока создавать новую oApp и читать ini файл, или, что явно лучше, хранить все данные oApp на С уровне.

Pasha: Поскольку с сервисом быстро сделать не получится, добавил в качестве примера утилиту letotray для запуска/останова сервера

Pasha: Что-то в сервере не нахожу функции HS_RECORDINFO А она вызывается. Потерялась ?

alkresin: Потерялась ? Без малейшего понятия.

sashaBG: Вот Пример для LetoDBTray на MiniGUI Ext (сб.83) Правда я тут прицепил и NETIO :) LETODB.EXE собран с harbour 1.0.1 RDDLETO.LIB с Харбуром из сборки MiniGUI Ext click here За основу взята INET_CHECKER Григория Филатова PS: На Tray Иконку Щелкать левой кнопкой

alkresin: Добавил source/server/leto_2.c - ядро, основанное на Harbour mt. Пару тестов прогнал - работает. На скорость и прочее не проверял еще. Makefile's еще не выкладывал. Если надо скомпилировать - в нужном makefile замените letocore.c на leto_2.c и hbvm.lib - на hbvmmt.lib

PSP: sashaBG, мне понравилось. :)

Andrey: sashaBG пишет: Вот Пример для LetoDBTray на MiniGUI Ext (сб.83) Классно ! И мне тоже понравилось. Только как перезапускать LetoDb с другого - удаленного компа ?

sashaBG: Вот Так click here только надо указать правильно IP адрес А в етой програмке предусмотрен перезапуск сервера , если он остановится по ошибке Сделайте letodb stop вручную и увидите как иконка становится красной а потом опять зеленой

Pasha: Я занимаюсь переводом PRG --> C для OpenTable и что там еще осталось

Pasha: alkresin пишет: Добавил source/server/leto_2.c - ядро, основанное на Harbour mt. Пару тестов прогнал - работает. На скорость и прочее не проверял еще. Makefile's еще не выкладывал. Если надо скомпилировать - в нужном makefile замените letocore.c на leto_2.c и hbvm.lib - на hbvmmt.lib На первый взгляд, все работает. Но я тоже только у себя тестировал, в работу не ставил. Хотя у меня и с прежней моделью сервер (собранный с xHarbour) не падал, так что я на таком уровне протестировать не смогу. alex_on, а ваша проблема с падением сервера не исчезла ? А как в дальнейшем предполагается использовать потоки ? Может быть, для каждого соединения создавать отдельный поток ? Так было бы логично, и с транзакцией было бы все как положено, и различные пользователи не мешали бы друг другу.

alx_on: Pasha пишет: alex_on, а ваша проблема с падением сервера не исчезла ? Пока только тестирую Нет времени с связи с переездом. Может быть, для каждого соединения создавать отдельный поток ? Слишком накладно (если соединений более 15). У нас доходит до 150 и более, при таком кол-во на переключение потоков будет времени уходить больше, чем на обработку команд

alkresin: А как в дальнейшем предполагается использовать потоки ? Может быть, для каждого соединения создавать отдельный поток ? Думать надо. Вариант с потоком на каждое соединение привлекателен своей простотой, но ... см.выше - Александр все правильно сказал. Тот же ADS использует фиксированное количество потоков, т.е. он как-то распределяет работу между ними. Скорее всего, на каждый запрос выделяется первый свободный поток, а если таковых нет, то запрос помещается в очередь. Тоже вариант, кстати. Но я бы предпочел, чтобы все транзакции выполнялись только одним потоком - при этом реализуется то их важное свойство, название которого я забыл :). Учитывая, что время исполнения транзакции сравнительно невелико - это не фильтрация, не индексация и т.п. - то ступора не должно быть. Для начала надо проверить и отработать механизм с hb_rddDetachArea() и hb_rddRequestArea().

Pasha: Транзакция (commit) и так выполняется на сервере одним запросом, так что это укладывается в схему фиксированного числа потоков. Правда, во время транзакции могут быть еще запросы на чтение данных. Для запросов на чтение требование выполнения в одном потоке критично ? Ведь их посылает один клиент, и следующий запрос не пройдет, пока не получен ответ по предыдущему. А количество потоков можно сделать настраиваемым - как в ADS к примеру. По умолчанию 8 с возможностью перенастройки.

alkresin: Транзакция (commit) и так выполняется на сервере одним запросом, так что это укладывается в схему фиксированного числа потоков. Не совсем понял, что вы имеете ввиду, но я говорил о том, чтобы все транзакции выполнялись в одном потоке, строго одна за другой, а не так, что одна транзакция в потоке А, а другая в это время параллельно в потоке Б.

Pasha: alkresin пишет: Не совсем понял, что вы имеете ввиду, но я говорил о том, чтобы все транзакции выполнялись в одном потоке, строго одна за другой, а не так, что одна транзакция в потоке А, а другая в это время параллельно в потоке Б. Теперь понятно, я говорил о другом

alx_on: alkresin пишет: одна транзакция в потоке А, а другая в это время параллельно в потоке Б Имелось в виду commit или весь период от начала до конца? Если только commit и совсем ничего не придумаем, то можно тупо блокировать потоки с транзакциями и обрабатывать commit по очереди

alkresin: Имелось в виду commit или весь период от начала до конца? Не понял. Какой период ? Какой фрагмент leto_Transaction() вы называете commit ? Зачем раздавать транзакции по потокам и блокировать их исполнение, а не просто выполнять их по очереди в одном потоке ?

alx_on: alkresin пишет: Какой период ? Какой фрагмент leto_Transaction() вы называете commit ? Имелось в виду с точки зрения клиентской части в том числе, т.е. LETO_COMMITTRANSACTION() Зачем раздавать транзакции по потокам и блокировать их исполнение, а не просто выполнять их по очереди в одном потоке ? Т.е. только один поток будет выполнять транзакции? А если все идет через транзации? Тогда в некоторых случаях мы не сможем разделить по потокам задачи.

alkresin: А если все идет через транзации? Так не бывает :). Какой смысл только добавлять информацию, если никто ее не читает, не анализирует, не печатает отчеты ? А получение данных - это как раз то узкое место, где может наступить ступор. Именно здесь имеет место фильтрация, операции типа leto_sum() и т.п. Да и такие ресурсозатратные операции, как индексация, упаковка происходят не во время транзакций.

alx_on: alkresin пишет: Так не бывает Бывает в случае множества клиентских подключений

alx_on: В новом варианте нашел две особенности 1. Перестал работать под Мак 2. В случае падения клиента информация о таблицах удаляется, но файлы при этом не закрываются. Т.е. попытка сервера открыть их повторно заканчивается ошибкой Пока сам с этим не разбирался.

alkresin: 1. Перестал работать под Мак Возможно, это связано с особенностями реализации под gcc - я его с Линуксом еще не проверял. 2. В случае падения клиента информация о таблицах удаляется, но файлы при этом не закрываются. Тут причина ясна. При падении клиента его удалением и закрытием таблиц занимается первый поток, в то время как открывает таблицы - второй ( я уже писал, что это может вызвать проблемы и в текущей реализации и это надо поправить ). В Harbour mt первый поток ничего не знает о таблицах, открытых во втором - вот и результат.

Pasha: Функции hs_sum(), hs_checkexpr(), IndexInfo(), hs_setfilter() сделал на C. Осталось еще сделать открытие/создание и dborderinfo

Pasha: letofunc.c строка 4446 Надо вставить: leto_SelectArea( ulAreaID, 0, NULL ); я пропустил :(

alkresin: Вставил.

Pasha: На сервере в нескольких местах вызывается hb_itemRelease( pAStru->itmFltExpr ); Надо ли перед этим вызывать hb_itemClear( pAStru->itmFltExpr ); нет ли утечки памяти ?

alkresin: В предыдущих версиях Harbour hb_itemClear() вызывался из hb_itemRelease(). Не думаю, что это изменилось, хотя проверить теперь труднее - там в коде куча каких-то макросов, лень разгребать. Во всяком случае, если б были утечки, то по завершении работы letodb вываливались бы соответствующие сообщения.

Pasha: Вижу в letodb.log такие записи: 22.06.10 12:34:49: Error BASE/1101 Argument error: LTRIM Arguments: ( [ 1] = Type: N Val: 0) 06/22/10 12:34:53: Leto DB Server has been started. и пребываю в недоумении. Видно, что сервер споткнулся на LTRIM и упал, затем стартовал снова. Непонято, на чем он споткнулся. В server.prg, errorsys.prg есть только конструкции вида LTrim( Str( ... ) ), т.е. LTrim получить числовой параметр никак не может, и тем не менее... Скорее всего ошибка возникла на OpenTable, но где ? В индексных выражениях у меня LTrim нет. В фильтре ? Так там стоит проверка

alkresin: От какого числа версия сервера ? letodb_crash.log есть ?

Pasha: Да самая последняя версия. letodb_crash.log нет Может, ошибка возникает в Str, она восстанавливается по Recover, за ней следующая ошибка в LTrim, которая уже не восстанавливается ? Или ошибка возникает прямо в errorsys ?

Pasha: Кто нибудь может собрать letodb с помощью mingw ? На sf пишут, что при сборке возникает ошибка, а какая - из лога не видно

alkresin: Да самая последняя версия. letodb_crash.log нет Не связано ли это с переводом функций фильтрации на С ?

Pasha: alkresin пишет: Не связано ли это с переводом функций фильтрации на С ? Я сейчас для эксперимента установил неправильный фильтр с LTrim по числовому полю В letodb.log появилась запись: 23.06.10 09:57:03: Error BASE/1101 Argument error: LTRIM Arguments: ( [ 1] = Type: N Val: 0) и сервер не упал. Все штатно, как и положено Да и вчера я только запускал программы, и больше ничего не делал. Поэтому и грешу на use Настраивал запуск со станций, где-то неправильно указывал каталоги, исправлял, и в какой-то момент сервер упал

alkresin: Кто нибудь может собрать letodb с помощью mingw ? Да, я только что собрал. Пришлось, правда, поправить makefile.gcc - каталог, где хранятся библиотеки, теперь другой. Но из log'а с SF видно, что он каталоги правил под свое окружение...

AlexMyr: Тоже собрал, ничего не правил.

Pasha: AlexMyr пишет: Тоже собрал, ничего не правил. Я ему сообщение отправил. Может, ошибка при сборке letodb.exe. По логу видно, что до этого этапа сборка доходит

Pasha: Есть 2 предложения. 1) Оптимизация вызова leto_PutRec. При вызове, скажем, dbCommit() - letoFlush выдавать серверу не 2 пакета - add/upd и flush, а все данные в одном пакете. Тоже самое делать при skip/seek/goto и где еще возможно. Конечно, это не касается транзакции. 2) Оптимизация вызовов dbCommit() dbUnlock() тоже заменой 2-х пакетов одним. Здесь хорошего решения не видно. Может быть ввести флажок: при commit делать сразу и unlock, и в этом случае unlock не выдавать ?

Pasha: Pasha пишет: Оптимизация вызова leto_PutRec. т.е., в команды flush, seek, goto и пр. добавить еще прицепной вагон с записью, и, если он есть, на сервере отрабатывать его

Pasha: Pasha пишет: Оптимизация вызовов dbCommit() dbUnlock() Надо все-таки реализовать на клиенте pLocksPos, тем более это все равно нужно. Тогда при вызове flush (если установлен флажок) можно будет делать сразу unlock. А при unlock проверять на клиенте pLocksPos, и, если он пуст, ничего не делать В результате мы получим один пакет при обновлении данных вместо трех

Pasha: Я смотрю, в leto_PutRec после if( bTransActive ) нет вызова free( szData ); наверное, он нужен

alkresin: нет вызова free( szData ); наверное, он нужен Да.

alkresin: Надо все-таки реализовать на клиенте pLocksPos, тем более это все равно нужно. Тогда при вызове flush (если установлен флажок) можно будет делать сразу unlock. А при unlock проверять на клиенте pLocksPos, и, если он пуст, ничего не делать Это хорошо, если программист пишет строго "как в книжке рекомендовано". А если он почему-то после commit опять начнет корректировать данные ?

Pasha: alkresin пишет: Это хорошо, если программист пишет строго "как в книжке рекомендовано". А если он почему-то после commit опять начнет корректировать данные ? Так инструмент дается тому, кто понимает, зачем он нужен и как его использовать. А если не понимает - проблемы индейцев шерифу безразличны. Кто не понимает, тот пусть не устанавливает этот флажок. Пусть это будет функция вида: Leto_UnlockOptimize( lOn/lOff ) и использование будет рекомендовано так: Leto_UnlockOptimize( .t. ) dbCommit() dbUnlock() Leto_UnlockOptimize( .f. )

alkresin: и использование будет рекомендовано так: Leto_UnlockOptimize( .t. ) dbCommit() dbUnlock() Leto_UnlockOptimize( .f. ) Тогда уж лучше какая-нибудь leto_Unlock() вместо этих четырех строк.

Andrey: А как по коду можно определить какой драйвер используется ? Т.е. LetoDB() или стандартный CDX ? Хочется иметь в одной задаче ОДНОВРЕМЕННО ДВА драйвера !!! Т.е. иметь локальный вариант и файл-серверный и LetoDB-драйвер. Соответственно в коде нужно будет тогда делать условия обработки: 1) для CDX 2) для LetoDB

Pasha: Andrey пишет: Хочется иметь в одной задаче ОДНОВРЕМЕННО ДВА драйвера !!! Да хоть 10 драйверов можно подключать. В dbUseArea 2-й параметр - это используемый rdd. Можно указаль LETO, или DBFCDX, или что угодно. Параметр есть и в dbCreate А проверка, какой драйвер используется в рабочей области - вызов RddName()

Pasha: Есть таблица размером 62М, 620 тыс. записей Создается тэг, в нем 3 индекса. Если запущен letodbtray, который здесь дал SashaBG, то при создании индекса может возникать ошибка: Create error (1-1081): 1081 - это argument error + Если не запущен letodbtray, то ошибка не возникает. letodbtray с интервалом в 1 сек вызывает leto_connect для проверки, жив ли сервер. Время индексации - примерно 10 сек. Я в лог добавляю аргументы при ошибке и вижу: 24.06.10 09:44:21: Create error (1-1081): Arguments: ( [ 1] = Type: C Val: 08232078, [ 2] = Type: N Val: 0)carecs.CDX индексное выражение для 1-го индекса такое: Stock+Code+DTOS(Date)+NDT 1-й аргумент "08232078" - это как раз Stock+Code. 2-й аргумент - это результат DTOS(), который нулем буть никак не может, но тем не менее... Т.е., вызов leto_connect() каким-то образом прерывает индексацию Сервер при этом не падает. PS Ошибка при LTrim - похоже из этой же серии, когда аргумент не может быть числовым, но тем не менее им оказывается.

Pasha: Т.е., вызов leto_connect() с другого клиента портит стек харбора

Pasha: Сервер был собран с xHarbour С Harbour ошибка возникает намного реже, но все равно возникает. С Harbour индексация выполняется немного быстрее, так что коллизия возникает реже

Pasha: Я использую xHarbour с кодовой страницей RU1251 Сейчас она называется RUWIN Если использовать клиенты xHb с сервером letodb, собранным с Harbour, то где-то надо транслировать имя кодовой страницы Подскажите красивое решение, где это лучше сделать.

Pasha: Pasha пишет: Т.е., вызов leto_connect() с другого клиента портит стек харбора Может быть, дело в вызове hb_retni() в функции hb_ipclose() ? Он там не нужен, его можно перенести в HB_FUNC( HB_IPCLOSE )

Pasha: Да, дело именно в этом, лечение помогло, теперь полет нормальный Надо еще пересмотреть остальные hb_ret* в этом модуле Может, и проблема alx_on в этом состояла

alkresin: Да, дело именно в этом, лечение помогло, теперь полет нормальный Здорово! Нашлась ошибка, которая реально могла доставлять проблемы.

alkresin: Если использовать клиенты xHb с сервером letodb, собранным с Harbour, то где-то надо транслировать имя кодовой страницы По-видимому, надо в строчку с версией, передаваемой клиенту при соединении, включить информацию о том, чем собран сервер ( Harbour/xHarbour ), тогда клиент при необходимости может, в соответствии с хранящейся у него таблицей, подменить название кодовой страницы.

Pasha: Хочется добавить в AREASTRU на сервере клиентский алиас таблицы Это понадобится в дальнейшем для выполнения клиентских процедур на сервере. Можно следать на сервере функцию, которая бы возвращала реальный алиас по клиентскому в окружении текущего пользователя, чтобы затем в процедуре по нему обращаться к таблице Для начала можно сделать хотя бы триггеры, тем более dbfcdx их поддерживает

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

Pasha: Выявил и устранил еще один неприятный глючек Блокируем запись по rlock Затем перемещаемся назад, что-то делаем, в том числе rlock - unlock на другой записи По skip возвращаемся на начальную запись Выдаем RLock. Клиент не перечитывает запись с сервера, поскольку она в есть буфере skip Затем по RLock клиент на сервер запрос не выдает, так считает что запись блокирована, а блокировка уже снята В результате при Commit получаем lock required Надо очищать буфер skip на клиенте при unlock Вопрос. В каких еще случаях это надо делать ?

Pasha: Попутно еще такой вопрос. RLock() блокирует только текущею запись. Если ранее была блокирована другая запись, то такая блокировка должна сниматься. А в leto на сервере в leto_RecLock структура pAStru->pLocksPos не очищается Это правильно ?

Pasha: На сервере где-то есть утечка памяти. Если запустить letodb совместно с letodbtray, и понаблюдать над ним через диспетчер задач, то видно, что память, используемая letodb, увеличивается. Т.е. утечка возникает при вызове leto_connect() - leto_disconnect() Пересмотрел пары hb_xgrab - hb_xfree, malloc - free, утечки не нашел. А она есть

Pasha: А уж какая утечка памяти в letodbtray... если из letodb едва сочится по капелькам, то из letodbtray хлещет вовсю

sashaBG: А каким образом ее поймать , где она я к сожалению не очень знаком со средствами выделения памяти и ее освобождения в Харборе Может ето потому что у меня Харбор не так собран , наверно надо с ключиками розобратся P.S. надо подучится

Pasha: Возможно, проблема в Leto_connect() - Leto_disconnect() в клиентской части leto. Во всяком случае, когда letodb не запущен, утечки в letodbtray нет.

Pasha: Мне кажется, что диспетчер задач windows врет, и врет сильно. На winxp sp1 память, используемая letodbtray, за 3 часа выросла с 8М до 70М. На winxp sp2 осталась почти такой же. Я в сервере добавил для LETO_MGGETINFO() еще 2 элемента - обьем памяти, так что можно будет отслеживать утечки А для letodbtray можно проверить память, вызывая Memory(1001)

Dima: Pasha пишет: Мне кажется, что диспетчер задач windows врет Нужно поюзать какую то альтернативную мерялку. Например http://www.securitylab.ru/software/234095.php

Pasha: Dima пишет: Нужно поюзать какую то альтернативную мерялку. Поставил. Результат практически такой же, как у task manager Для xp sp1 у letodbtray память дошла уже почти до 100М, а для sp2 - почти тоже самое. Непонятно. это в самой windows трубы ржавые ? Может быть конечно, еще minigui протекает А использование Memory() показывает, что на клиенте при connect - disconnet утечки нет. На сервере при каких-то операциях есть утечка несколько сот байт, а в каких - надо выяснять

Dima: Pasha пишет: Непонятно. это в самой windows трубы ржавые ? Возможно ;) Не зря ведь был SP2 а затем SP3

AlexMyr: Сегодня локально запускал и останавливал сервер. В letodb.log формат даты меняется: 06/30/10 08:28:14: Leto DB Server has been started. 06/30/10 08:34:24: Server has been closed. 06/30/10 09:16:34: Leto DB Server has been started. 30.06.2010 11:05:13: Server has been closed. 06/30/10 11:05:14: Leto DB Server has been started. 30.06.2010 12:54:07: Server has been closed. 06/30/10 12:54:14: Leto DB Server has been started. 06/30/10 12:54:35: Server has been closed. 06/30/10 12:54:39: Leto DB Server has been started. 06/30/10 12:55:27: Server has been closed. 06/30/10 12:55:36: Leto DB Server has been started. 30.06.2010 14:49:55: Server has been closed. 06/30/10 14:50:14: Leto DB Server has been started. 06/30/10 14:50:37: Server has been closed. 06/30/10 14:50:46: Leto DB Server has been started.

AlexMyr: В letodb.ini Pass_for_Login = 1 Pass_for_Data = 1 Добавил пользователя с правами NNN В программе через HBROWSE (HWGUI) при попытке изменить данные вылазит ошибка Error LETO/1021 Помилка в тип? даних Called from DBUNLOCK(0) Called from HBROWSE:EDIT(3153) Called from HBROWSE:ONEVENT(551) Called from HWG_ACTIVATEMAINWINDOW(0) Called from HMAINWINDOW:ACTIVATE(355) Called from MAIN(107) HwGUI 2.17 Harbour 2.1.0beta2 (Rev. 14944) Date:30.06.2010 Time:14:56:39 При Pass_for_Data = 0 без ошибок т.к. права не проверяются. Что делать? Проверять локально права пользователя и давать (не давать) добро на редактирование в HBROWSE? Как правильно?

alkresin: Pasha пишет: Я в сервере добавил для LETO_MGGETINFO() еще 2 элемента - обьем памяти, так что можно будет отслеживать утечки Вот это, IMHO, зря. Зачем нагружать сервер сбором и пересылкой не имеющей отношения к letodb информацией, зачем клиенту знать, что там с памятью на сервере ? У администратора есть и другие средства для этого. Что касается утечки при connect / disconnect ... В кодах leto вроде все чисто. Может, проблема, действительно, в недрах реализации ip в SP1. У меня серверы под Линуксом работают, там я такого не наблюдал.

Pasha: По поводу утечки в letodbtray, или подобной утилиты, в winxp sp1 Вызов Memory(1001) показывает, что память не увеличивается, остается постоянной, байт в байт. Сначала я попробовал вызывать hb_gcAll(.t.), результата это не дало Затем применил другую схему: вместо вызова connect - disconnect при старте соединяюсь с сервером, затем по таймеру опрашиваю его вызовом Leto_MgGetInfo(). Такой чопик помог, утечка практически прекратилась. Вернее, память в task manager увеличивается, но на самую малось

alkresin: AlexMyr пишет: Сегодня локально запускал и останавливал сервер. В letodb.log формат даты меняется: В промежутке между стартом /остановом, наверное, программы какие-то запускались. При подсоединении пользователя формат даты передается на сервер, хотя, конечно, он должен только для этого пользователя работать. Надо будет посмотреть ...

Pasha: alkresin пишет: Вот это, IMHO, зря. Зачем нагружать сервер сбором и пересылкой не имеющей отношения к letodb информацией, зачем клиенту знать, что там с памятью на сервере ? У администратора есть и другие средства для этого. Так у администратора сейчас единственное средство пощупать letodb - это утилита manage. Туда я и добавил этот вызов. Если сервер собирать без fmstat, то эта добавка на работу сервера никак не скажется, разве что клиенту будет пересылаться дополнительно 2 нуля, то есть 4 байта: "0;0;"

alkresin: AlexMyr пишет: Что делать? Проверять локально права пользователя и давать (не давать) добро на редактирование в HBROWSE? Тут подумать надо. Локально права пользователя вы так просто не проверите - ведь если у него админ прав нет, то он их не прочитает с сервера. Можно, конечно, не возвращать ошибку в такой ситуации, а, не изменяя данные, сказать что все Ок - но это, наверное, неправильно. Так что предлагайте варианты.

alkresin: Так у администратора сейчас единственное средство пощупать letodb - это утилита manage Ну есть же всякие process explorer'ы ... Или у администратора физически нет доступа к сереверу ?

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

alkresin: Наткнулся на одну ошибку - seek по отфильтрованной базе неправильно работает, если фильтр выполняется на стороне клиента ( это когда в нем присутствуют переменные, user defined функции, алиасы ). Надо будет исправить, не знаю только когда - со временем туго.

AlexMyr: alkresin пишет: В промежутке между стартом /остановом, наверное, программы какие-то запускались. При подсоединении пользователя формат даты передается на сервер, хотя, конечно, он должен только для этого пользователя работать. Я игрался только с editable в HBROWSE и менял Pass_for_Data в letodb.ini, больше ничего не трогал в программе. Сервер не пересобирал, тоько останавливал и запускал. Как по мне то в letodb.log должно записываться с теми установками с какими собирался сервер, а юзеру то что хочет юзер (мое ИМХО).

AlexMyr: alkresin пишет: Тут подумать надо. Локально права пользователя вы так просто не проверите - ведь если у него админ прав нет, то он их не прочитает с сервера. Можно, конечно, не возвращать ошибку в такой ситуации, а, не изменяя данные, сказать что все Ок - но это, наверное, неправильно. Так что предлагайте варианты. Сейчас получается, что юзер с правами NNN в HBROWSE заходит в режим редакирования (может случайно или нет по enter или двойному клику) и этим блоктрует запись, уходит пить кофе, чем не дает возможность править данные другим с правами NNY, что не есть правильно. И сервер не знает в каком режиме клиентская сторона с HBROWSE:acolumns:leditable равна true или false, и в других режимах редактирования данных. Получается, что юзера с правами NNN нужно сначала проверить, что он хочет делать (добавить, изменить, удалить), а потом серверу решить, что делать. На первых порах предлагается молча оставить данные как есть и не возвращать ошибки.

alkresin: Сейчас получается, что юзер с правами NNN в HBROWSE заходит в режим редакирования (может случайно или нет по enter или двойному клику) и этим блоктрует запись, Стоп. Заходя в режим редактирования в HBROWSE, пользователь не блокирует запись. Блокировка осуществляется только в момент записи в БД.

AlexMyr: Я извиняюсь, не проверял так щательно работу блокировок. Тогда хотелось бы для юзера с правами NNN как-то убрать возможность вообще зайти в режим редактирования. Это сейчас наверное невозможно сделать

Pasha: alkresin пишет: Ну есть же всякие process explorer'ы ... Или у администратора физически нет доступа к сереверу ? Тот же task manager возвращает другую информацию. А мне надо было глянуть, что на сервере происходит с памятью на уровне харбора. Да и операция это самая что ни есть безобидная: если работет fmstat, то hb_xquery возвращает static-переменную, ничего не расчитывая при этом

Pasha: alkresin пишет: Наткнулся на одну ошибку - seek по отфильтрованной базе неправильно работает, если фильтр выполняется на стороне клиента ( это когда в нем присутствуют переменные, user defined функции, алиасы ). Надо будет исправить, не знаю только когда - со временем туго. Так такой фильтр на сервере не будет установлен. А в чем прояляется эта ошибка ?

alkresin: Так такой фильтр на сервере не будет установлен. А в чем прояляется эта ошибка ? Ошибка в том, что seek возвращает запись без учета фильтра. Т.е. там надо написать дополнительный код в leto_Seek() leto1.c, который в том случае, если таблица фильтруется на стороне клиента, проверял бы соответствие найденной записи фильтру и при необходимости делал бы skip до достижения нужной записи.

Pasha: alkresin пишет: Т.е. там надо написать дополнительный код в leto_Seek() leto1.c т.е. в LetoSeek после ParseRec надо добавить: SELF_SKIPFILTER( ( AREAP ) pArea, ( bFindLast ? -1 : 1 ) ); вечером добавлю

alkresin: т.е. в LetoSeek после ParseRec надо добавить: SELF_SKIPFILTER( ( AREAP ) pArea, ( bFindLast ? -1 : 1 ) ); Этого недостаточно. Надо еще соответствие индексному ключу проверять - при softseek off если в найденной по skipfilter записи ключ не тот, надо идти на eof

Pasha: Действительно. Еще надо scope на клиенте проверять. Эту проверку лучше вставить прямо в letoSkipFilter, чтобы сработало и при go top, и при go bottom

Pasha: Нет, не надо, scope сервер проверит

Pasha: Поправил seek, проверьте пожалуйста

AlexMyr: Как узнать права юзера под которым зашел на сервер (ф-я leto_MgGetUsers() возвращает IP)? Идея такая: захожу юзером, проверяю права, допустим на запись, и потом в HBROWSE lEditable устанавливаю в .T. или .F.

alkresin: Как узнать права юзера под которым зашел на сервер (ф-я leto_MgGetUsers() возвращает IP)? В данный момент - никак. Надо будет добавить функцию.

alkresin: Поправил seek, проверьте пожалуйста У меня ошибка линковки - undefined hb_itemGetTD

AlexMyr: alkresin пишет: В данный момент - никак. Надо будет добавить функцию. Будем ждать

AlexMyr: alkresin пишет: У меня ошибка линковки - undefined hb_itemGetTD У меня собралось без ошибок.

alkresin: У меня Harbour старый - 1.0

Pasha: Вместо hb_itemGetTD( pValue ) поставьте hb_itemGetDL( pValue ) Все равно в индексном выражении время не встречается

alkresin: Проверил seek на фильтрованном наборе - теперь, вроде, все нормально. Спасибо.

alkresin: Коллеги, обязательно отмечайте в Changelog'е, что изменяется протокол передачи данных и надо перекомпилировать сервер, чтобы он нормально работал с вновь перекомпилированными клиентами. Я сегодня почти час искал почему не работает dbcreate() - оказалось, что введен новый параметр pCreateInfo->atomAlias ( а нужен ли он ?? ) посреди ( а почему не в конце - тогда бы не было проблемы ) команды creat; Пока мне пришлось его убрать у себя, чтобы перекомпилировать проблемный программный модуль, т.к. я не могу так просто остановить сервер, с которым работает куча людей...

Pasha: Хорошо А параметр этот нужен, поскольку dbCreate может вызываться в режиме KeepOpen

Pasha: Если открывается таблица, уже открытая другим пользователем, то после открытия надо делать go top. Сейчас пользователю передается запись, которая является текущей для другого пользователя, что не хорошо. Вечером скину изменение на CVS

Pasha: Второй раз сталкиваюсь с ситуацией, когда на win98 невозможно соединиться с сервером. leto_connect дает ошибку. Попробовал использовать другой порт - результат тот же. При этом соседние компьютеры с win98/xp работают нормально В первом случае переустановил windows, поставил xp, и вопрос был исчерпан. Но не всегда возможно поставить xp, если win98 лиценционный. Второй случай совсем непонятный. Компьютер с win98 несколько недель успешно проработал с letodb, и после безобидной операции: удаление планировщика drweb и очистка корзины перестал соединяться с leto. Переустановка windows 98 поверх не помогла. Полная переустановка думаю поможет, но хотелось бы разобраться, в чем дело. Где можно копать в 98-й ? Какие средства отвечают за работу с сокетами ? Что можно посмотреть в реестре ? Какую диагностику выдать в клиенте leto ?

alkresin: Хм... Я с таким не сталкивался, хотя у меня на работе компьютеров с win98 больше десятка. А сеть на них работает нормально ? Ping проходит ? Если сервер пингуется, я не вижу ни одной причины, почему может быть проблема с соединением. У меня немало случаев, когда сетевые средства windows отказывают - компьютер перестает быть виден в сети, проходит только ping - но letodb работает при этом нормально.

Pasha: Да, пинг работает, и раньше соединение с сервером было по айпи адресу, и успешно работало. Деинсталляция антивируса тоже ничего не дала. Брандмауэра на 98-й нет.

alkresin: Попробуйте в leto_ConnectionNew() leto_writelog'и расставить, чтобы установить - это connect не работает или команда intro; не отрабатывает

Pasha: Уже ставил, в первом случае. Не работает connect. Во втором случае не пробовал.

Andrey: Pasha пишет: Второй раз сталкиваюсь с ситуацией, когда на win98 невозможно соединиться с сервером. А win98 какой ? Если не SE то надо бы ставить от DELPHI пакет для SOKET'oв. В свое время намучился с ним.

Pasha: se конечно. А что за пакет такой и при чем тут delphi ?

alkresin: Попробуйте приконнектиться к серверу телнетом: telnet.exe _ip_address_ _port_ С командами только поосторожнее - я тут сейчас попробовал intro; выдать - сервер рухнул ( надо проверить, почему - ошибка в командной строке не должна к такому приводить ).

AlexMyr: alkresin пишет: цитата: Как узнать права юзера под которым зашел на сервер (ф-я leto_MgGetUsers() возвращает IP)? В данный момент - никак. Надо будет добавить функцию. Александр! большое спасибо, с функцией нормально все проходит. Но! Если я забыл проверить права юзера и он редактирует данные, то получаем ошибку Error LETO/1021 Ощибка в типе данных Called from DBUNLOCK(0) Called from HBROWSE:EDIT(3153) Called from HBROWSE:ONEVENT(551) Called from HWG_ACTIVATEMAINWINDOW(0) Called from HMAINWINDOW:ACTIVATE(355) Called from MAIN(116) HwGUI 2.17 Harbour 2.1.0beta2 (Rev. 15011) Date:08.07.2010 Time:08:30:50 Надо серверу либо тихо пропустить попытку юзера что-то изменить, либо выдать сообщение типа "Редактирование запрещено!"

alkresin: Надо серверу либо тихо пропустить попытку юзера что-то изменить, либо выдать сообщение типа "Редактирование запрещено!" Выдачу сообщения я не очень себе представляю. Как клиент будет обрабатывать такое сообщение ? Будете ставить BEGIN SEQUENCE ... END SEQUENCE на каждый REPLACE ? А молча не записать - не уверен, что это правильно. Вот аналогия - если мы открываем dbf как readonly, а потом пытаемся туда записывать данные, то Clipper/Harbour выдает как раз ошибку записи.

Pasha: Telnel тоже не коннектился. Попытки найти повреждения в dll, относящихся к winsock, в соответвующих ветках реестра ничего не дали. Socket не соединяется - и хоть ты тресни Но людям то работать надо, поэтому изыскания пришлось прекратить, переустановить win98, и вопрос был исчерпан

Pasha: Возникает потребность кроме доступа к БД иметь еще доступ к метаданным, находящимся на сервере: у настройкам, скриптам, файлам hrb, тем же отчетам fastreport. В связи с этим возникает соблазн сделать аналог файлового доступа через leto: fopen - fread - fclose. Мне было бы достаточно доступа только на чтение, но неизбежно возникнет соблазн сделать и аналог fwrite. В связи с этим вопрос: а стоит ли ? Сделать то это легко, но надо ли ?

AlexMyr: Pasha пишет: Возникает потребность кроме доступа к БД иметь еще доступ к метаданным, находящимся на сервере Тоже есть необходимость доступа к текстовым файлам (нужно передавать их от клиента к клиенту, сейчас просто расшарил папку на сервере с текст. файлами), но мне кажется, что это задача не для leto. Сейчас по немногу экспериментирую с библиотекой hbtip и ftp-сервером для этих целей.

Pasha: Впечатления от letodb у меня самые благоприятные. Работает надежно. Если установлен на постоянно включенном компьютере - не свалился ни разу. Было выявлено несколько ошибок и несовместимостей с dbfcdx, практически обо всех я здесь писал, и все они были моментально устранены. Конечно, функциональная совместимость с dbfcdx не 100%, но близко от того. Да и 100%-й совместимости не будет. Впечатления у пользователей: там, где обьемы БД значительные и критична производительность: "Стало намного быстрее". Конечно, я кое-что специально оптимизировал

Наиль: alkresin пишет: Может, проблема, действительно, в недрах реализации ip в SP1 Раньше у меня был SP2. Сначала я грешил, на глюки официального ICQ, когда он проработав 2-3 дня съедал всю память моего компьютера, но когда обнаружил, что MailAgent ведёт себя идентично, то пришёл к выводу, что это всё-таки винда виновата. Pasha пишет: В связи с этим возникает соблазн сделать аналог файлового доступа через leto: fopen - fread - fclose. В связи с этим вопрос: а стоит ли ? Если бы leto был поделкой ради забавы, тогда, может, и стоило бы. А серьёзный продукт должен обеспечивать безопасность. А это значит настройка прав доступа на стороне сервера средствами Leto. Хотя ftp не является оптимальным по требованиям безопасности, но он лучше всего подходит для подобной задачи. Даже лучше, чем расшаривание папок, хотя расшаривание самое удобное. Конечно, возможна прямая передача данных через сокеты, но решение о том, какие данные должны передаваться, должен решать только сервер.

Pasha: Наиль пишет: Если бы leto был поделкой ради забавы, тогда, может, и стоило бы. А серьёзный продукт должен обеспечивать безопасность. А это значит настройка прав доступа на стороне сервера средствами Leto. Хотя ftp не является оптимальным по требованиям безопасности, но он лучше всего подходит для подобной задачи. Даже лучше, чем расшаривание папок, хотя расшаривание самое удобное. Конечно, возможна прямая передача данных через сокеты, но решение о том, какие данные должны передаваться, должен решать только сервер. Вопрос не в безопасности. Права доступа можно обеспечить теми же средствами, какие уже имеются в leto. Вопрос в другом. Сейчас доступ к таким данным можно обеспечить, скажем, через hbnetio. Но тогда возникает вопрос: зачем иметь 2 соединения, 2 сервера, отдельно настраивать для каждого права, когда лучше иметь все это в одном флаконе

Pasha: Кстати, насколько реальна идея скрестить ужа с ежом, т.е использовать netio в качестве транспортного протокола для letodb ?

Pasha: Подзабыл C. Какой предел у malloc для выделения памяти в 32-х битных системах ? 64K ? Не будет ли переполнения SkipBuf, если значение достаточно большое ? Захотелось вот получать всю выборку одним пакетом: LETO_SETSKIPBUFFER(1000) dbEval(...) LETO_SETSKIPBUFFER(10) и возникли сомнения... Может заменить на hb_xgrab ? В связи с этим возникла мысль паковать большие пакеты при передаче

Pasha: Смотрю: #define HB_SENDRECV_BUFFER_SIZE 16384 т.е. сейчас пакет не может быть больше 16К ?

alx_on: Выложил свои правки... Вопрос по падению старой версии остается в силе (кто-то здесь упоминал меня после некоторых исправлений в коде :) ) Так вот: падения остались в самых неожиланных местах. Может 3 дня проработать, может сразу упасть.

alkresin: Подзабыл C. Какой предел у malloc для выделения памяти в 32-х битных системах ? 64K ? http://en.wikipedia.org/wiki/Malloc : The largest possible memory block malloc can allocate depends on the host system, particularly the size of physical memory and the operating system implementation. Theoretically, the largest number should be the maximum value that can be held in a size_t type, which is an implementation-dependent unsigned integer representing the size of an area of memory. The maximum value is 2CHAR_BIT*sizeof(size_t) − 1, or the constant SIZE_MAX in the C99 standard. Как я понял, можно запрашивать достаточно много, 64К ограничения нет. Может заменить на hb_xgrab ? Так hb_xgrab использует как раз malloc.

alkresin: В связи с этим возникает соблазн сделать аналог файлового доступа через leto: fopen - fread - fclose. Мне было бы достаточно доступа только на чтение, но неизбежно возникнет соблазн сделать и аналог fwrite. В связи с этим вопрос: а стоит ли ? Сделать то это легко, но надо ли ? Я считаю, что стоит сделать - естественно, с обеспечением безопасности. Только, может, аналоги не fopen и Co, а memoread/memowrite, это проще и, наверное, достаточно.

alkresin: #define HB_SENDRECV_BUFFER_SIZE 16384 т.е. сейчас пакет не может быть больше 16К ? Это размер пакетов, на которые socket - функции разбивают исходный пакет.

Andrey: Pasha пишет: В связи с этим возникает соблазн сделать аналог файлового доступа через leto: fopen - fread - fclose. Мне было бы достаточно доступа только на чтение, но неизбежно возникнет соблазн сделать и аналог fwrite. В связи с этим вопрос: а стоит ли ? Сделать то это легко, но надо ли ? Нужно ОБЯЗАТЕЛЬНО ! Я еще в начале просил это делать ! Пример из практики, принесли базу из отдела соц.защиты, кто получает деньги... (порядка 30 000 записей, бывает больше). Нужно в программу Субсидии (базы на сервере) удалить старые записи и добавить эти новые ! Задача в лоб - программа перебрасывает записи с клиента на сервер 4 часа !!! Это не моя программа, на Delphi7 написана, работает через SocketServer Дельфовый... Такие задачи встречаются постоянно !!! Если на сервер можно записать ZIP-файл, там его распаковать и добавить через APPEND FROM - прошло бы меньше времени ! На вскидку минут 10 - 15. НАДО !!!

Andrey: alkresin пишет: Только, может, аналоги не fopen и Co, а memoread/memowrite, это проще и, наверное, достаточно. Нет не пойдет ! Давайте полностью !!! Файлы форм *.FR3 тоже хочу хранить на сервере ! Обновление EXE файла на клиентских местах ХОЧУ тоже делать через LetoDB !!! ----------------------------------------------------------------------------------------------------------------------- Лучше 3 дня учиться и за 5 минут долететь !!! (Фраза из мультика "Ноги и крылья" )

AlexMyr: alkresin пишет: Только что открыл на Sourceforge новый проект - Leto DB Server - https://sourceforge.net/projects/letodb Это мультиплатформенный ( Windows, Unix/Linux ) сервер баз данных, предоставляющий клиентским программам доступ к dbf/cdx файлам, находящимся на удаленном сервере Вроде начиналось все с сервера баз данных, а сейчас уже смотрим в сторону файл-сервера, потом захотим принт-сервер Andrey пишет: Такие задачи встречаются постоянно !!! Если на сервер можно записать ZIP-файл, там его распаковать и добавить через APPEND FROM - прошло бы меньше времени ! На вскидку минут 10 - 15. А хто будет распаковывать на сервере? letodb? Letodb как раз для таких задач как добавить, отредактировать, удалить запись и тд. И будет наверное быстрей добавить записи нежели тащить на сервер тяжелый zip, распаковать и добавить записи. А потом чтобы не засорять сервер еще надо будет удалить этот zip.

alkresin: Файлы форм *.FR3 тоже хочу хранить на сервере ! А зачем для этого полный набор файловых функций ? Разве недостаточно с сервера забрать эту форму целиком с помощью предполагаемой leto_memoread() ? Обновление EXE файла на клиентских местах ХОЧУ тоже делать через LetoDB !!! В этих целях я себе отдельный сервер сделал, назвал - letofc. В ini - файле на сервере храню названия программ как имена секций и в каждой секции - список каталогов и файлов, используемых этой программой. При присоединении к серверу клиент сообщает имя программы и получает в ответ список файлов с датами/временем их создания и запрашивает обновившиеся.

Andrey: alkresin пишет: В этих целях я себе отдельный сервер сделал, назвал - letofc. В ini - файле на сервере храню названия программ как имена секций и в каждой секции - список каталогов и файлов, используемых этой программой. При присоединении к серверу клиент сообщает имя программы и получает в ответ список файлов с датами/временем их создания и запрашивает обновившиеся. А поподробнее ? Хочу пример .... Заранее спасибо !!!

Andrey: AlexMyr пишет: А хто будет распаковывать на сервере? letodb? А свои процедуры на что ? Сделаю свою процедуру и прикручу к серверу !

Pasha: alx_on пишет: Выложил свои правки... Александр, а зачем вы поменяли формат в leto_Sum ? sprintf(ptr, "%lu", pSums[ usIndex ].value.lSum); Ведь это не ULONG, а LONG, знак потеряется

Pasha: Правильнее будет %ld А в строке 3007 изменение существенно ? Это была ошибка ? USHORT i = 0; на USHORT i = 1;

alx_on: Pasha пишет: sprintf(ptr, "%lu", pSums[ usIndex ].value.lSum); Ведь это не ULONG, а LONG, знак потеряется не ту версию выложил :( правил предупреждения при компиляции (был совсем странный вариант %d) А в строке 3007 изменение существенно ? Это была ошибка ? ошибка не критическая (возвращала больше на одну запись)

Pasha: alx_on пишет: ошибка не критическая (возвращала больше на одну запись) Т.е, память выделялась на 10 записей, а возвращалось 11. Правда, запись как правило занимает меньший размер при передаче, так что обычно памяти хватало. Но все-таки, в каких-то случаях могло и не хватить, хорошо что заметили

alx_on: К вопросу о фильтрах совместно с SCOPE Глючит :( Самое интересное - в новом варианте (MT) все работает (по крайней мере, в найденном случае) Смотрю...

Pasha: А что глючит ? Я не замечал. Хотя у меня сервер собран через xHarbour



полная версия страницы