Форум » 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)



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