Форум » 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 на Харборе, ... и вообще все в наших руках :). Кто хочет участвовать в разработке, тестировании - пишите.

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

alx_on: Pasha пишет: А что глючит ? простой SKIP Если выполнить выражение фильтра на записи, то все правильно (.F.) Если SKIP, то на нее переходит (хотя не должен)

Pasha: А фильтр серверный или клиентский ? С серверным должно быть все ok

alx_on: Pasha пишет: А фильтр серверный или клиентский ? клиентский


Pasha: Уже вижу, в letoSkipRaw нет проверки на клиентский фильтр для буфера skip. Надо добавить. А scope тут ни при чем

alx_on: Pasha пишет: в letoSkipRaw нет проверки на клиентский фильтр для буфера skip Как тогда работает MT вариант? :)

Pasha: Непонятно Точно клиентский фильтр ? Т.е. сервер не может вычислить выражение фильтра, или задан только блок кода для фильтра ?

AlexMyr: К вопросу о файловом доступе: А если реализовать это через BLOB поля? Вот пример без letodb (проверял работает) #include "blob.ch" FUNCTION SHOWPIX() LOCAL cPixFile := "ntimage.gif" LOCAL nPos REQUEST DBFCDX rddSetDefault( "DBFCDX" ) dbCreate( "customer", { { "PIX","W",10,0 } } ) USE Customer NEW dbAppend() nPos := FieldPos( "Pix" ) BLOBIMPORT( nPos, "ved.prg" ) dbAppend() IF !BLOBIMPORT( nPos, cPixFile ) Alert( "Export of picture " + cPixFile + " failed!" ) ENDIF dbAppend() BLOBIMPORT( nPos, "test_ta.exe" ) dbgotop() BLOBEXPORT( nPos, "ved_new.prg", 0 ) dbGoBottom() BLOBEXPORT( nPos, "test_ta_new.exe", 0 ) return Если собрать этот пример с letodb, то letodb не может создать файл с полем типа W (blob поле), а если создать с MEMO полем, то letodb выдает ошибку: Error LETO/0 Operation not supported Called from DBFILEPUT(0) Called from SHOWPIX(17) Кто что скажет по поводу BLOB полей?

alx_on: Pasha пишет: сервер не может вычислить выражение фильтра да LETO_ISFLTOPTIM() - .F.

Pasha: AlexMyr пишет: Кто что скажет по поводу BLOB полей? А что тут говорить... надо добавить в leto поддержку HB_FT_BLOB, HB_FT_PICTURE, HB_FT_OLE Сейчас поддерживается только HB_FT_MEMO Я использую memo, и проблем не было, ни с M, 10, ни с M, 4

Pasha: В M, 4 я храню в том числе и картинки jpg. Сейчас проверил - работает и на чтение, и на запись

Pasha: Кстати, старый Harbour 1.0 знает, что такое HB_FT_BLOB, HB_FT_PICTURE, HB_FT_OLE ?

AlexMyr: Pasha пишет: Кстати, старый Harbour 1.0 знает, что такое HB_FT_BLOB, HB_FT_PICTURE, HB_FT_OLE ? Скорее всего да. В файле whatsnew.txt сказано: Version 0.46 Alpha Build 46 (2006-05-29) tag: build46 ... - Added all Clipper 5.3 BLOB*() functions support. - Added new RDD DBFBLOB compatible with Clipper 5.3 DBFBLOB. It operates on memo files only (.dbv) without tables (.dbf). ...

Pasha: blob и прочая я уже добавил, вечером скину

Pasha: alx_on пишет: да LETO_ISFLTOPTIM() - .F. Странно это. Я сейчас проверил - skip правильно отрабатывает клиентский фильтр. Тогда понятно только то, что ничего не понятно :(

alx_on: Pasha пишет: Тогда понятно только то, что ничего не понятно Вот и я о том же

alx_on: Нашел проблему с фильтром Была интересная проверка на длину LETO_MAX_EXP У меня фильтр был больше и это воспринималось как снятие фильтра! Выложу исправления - проверьте плз Вопрос Александру: в каких глобальных целях используется функция leto_ParseFilter()? Были какие то нюансы при простой проверке? (т.е. просто попробовать скомпилять блок кода) Потому как его надо допиливать на предмет добавления проверки "FIELD->". Стоит это делать?

alkresin: Вопрос Александру: в каких глобальных целях используется функция leto_ParseFilter()? Представьте такое выражение фильтра: SOME_FIELD == 1 .AND. Some_UDF() Если мы его выполняем (для проверки) при текущем значении SOME_FIELD != 1, возвращается логическое выражение .F. и никакой ошибки, т.к. до выполнения Some_UDF() дело не доходит - получается, что выражение годно для выполнения на сервере, что неверно.

alkresin: Потому как его надо допиливать на предмет добавления проверки "FIELD->". А зачем использовать field-> в выражении для фильтра ?

alx_on: alkresin пишет: Если мы его выполняем (для проверки) Уже просто компиляция вернет ошибку (нет функции Some_UDF) А зачем использовать field-> При строгой проверке (ключ -w3) без "FIELD->" макрокоманда "SET FILTER" не компиляется

AlexMyr: Не могу собрать letodb, hbmk2: Processing local make script: hbmk.hbm hbmk2: Compiling Harbour sources... hbmk2: Harbour compiler command (embedded): (c:\dev\harbour\bin\harbour.exe) -n1 source\client\rddsys.prg -n -w -q0 -es2 -olib\.hbmk\win\bcc\ -ic:\dev\harbour\include -iinclude hbmk2: Compiling... hbmk2: C/C++ compiler command: bcc32.exe -c -q -d -6 -O2 -OS -Ov -Oi -Oc -tWM -w -Q -w-sig- -nlib\.hbmk\win\bcc -Ic:\dev\harbour\include -Iinclude lib\.hbmk\win\bcc\rddsys.c source\client\leto1.c source\client\letomgmn.c source\common\blowfish.c source\common\common_c.c source\common\hbip.c source\common\net.c lib\.hbmk\win\bcc\rddsys.c: source\client\leto1.c: Error E2451 source\client\leto1.c 490: Undefined symbol 'HB_FT_PICTURE' in function letoIsBinaryField Warning W8057 source\client\leto1.c 497: Parameter 'uiType' is never used in function letoIsBinaryField Warning W8057 source\client\leto1.c 497: Parameter 'uiLen' is never used in function letoIsBinaryField Error E2451 source\client\leto1.c 625: Undefined symbol 'HB_FT_PICTURE' in function leto_ParseRec Error E2172 source\client\leto1.c 625: Duplicate case in function leto_ParseRec Warning W8019 source\client\leto1.c 626: Code has no effect in function leto_ParseRec Error E2379 source\client\leto1.c 626: Statement missing ; in function leto_ParseRec Error E2451 source\client\leto1.c 1786: Undefined symbol 'HB_FT_PICTURE' in function letoGetValue Error E2172 source\client\leto1.c 1786: Duplicate case in function letoGetValue Warning W8019 source\client\leto1.c 1787: Code has no effect in function letoGetValue Error E2379 source\client\leto1.c 1787: Statement missing ; in function letoGetValue Error E2451 source\client\leto1.c 2196: Undefined symbol 'HB_FT_PICTURE' in function letoPutValue Error E2172 source\client\leto1.c 2196: Duplicate case in function letoPutValue Warning W8019 source\client\leto1.c 2197: Code has no effect in function letoPutValue Error E2379 source\client\leto1.c 2197: Statement missing ; in function letoPutValue Error E2451 source\client\leto1.c 2692: Undefined symbol 'HB_FT_PICTURE' in function letoCreate Error E2172 source\client\leto1.c 2692: Duplicate case in function letoCreate Error E2188 source\client\leto1.c 2693: Expression syntax in function letoCreate Error E2451 source\client\leto1.c 2991: Undefined symbol 'HB_FT_PICTURE' in function letoOpen *** 14 errors in Compile *** source\client\letomgmn.c: Warning W8075 source\client\letomgmn.c 116: Suspicious pointer conversion in function HB_FUN_LETO_FILE Warning W8075 source\client\letomgmn.c 143: Suspicious pointer conversion in function HB_FUN_LETO_FERASE Warning W8075 source\client\letomgmn.c 176: Suspicious pointer conversion in function HB_FUN_LETO_FRENAME Warning W8075 source\client\letomgmn.c 628: Suspicious pointer conversion in function HB_FUN_LETO_VARSET Warning W8075 source\client\letomgmn.c 635: Suspicious pointer conversion in function HB_FUN_LETO_VARSET Warning W8080 source\client\letomgmn.c 797: 'cType' is declared but never used in function HB_FUN_LETO_VARINCR Warning W8080 source\client\letomgmn.c 834: 'cType' is declared but never used in function HB_FUN_LETO_VARDECR Warning W8080 source\client\letomgmn.c 866: 'lValue' is declared but never used in function HB_FUN_LETO_VARDEL Warning W8080 source\client\letomgmn.c 866: 'cType' is declared but never used in function HB_FUN_LETO_VARDEL Warning W8075 source\client\letomgmn.c 871: Suspicious pointer conversion in function HB_FUN_LETO_VARGETLIST Warning W8080 source\client\letomgmn.c 955: 'ui' is declared but never used in function HB_FUN_LETO_VARGETLIST source\common\blowfish.c: source\common\common_c.c: source\common\hbip.c: Warning W8084 source\common\hbip.c 184: Suggest parentheses to clarify precedence in function hb_ipInit source\common\net.c: hbmk2: Error: Running C/C++ compiler. 1 bcc32.exe -c -q -d -6 -O2 -OS -Ov -Oi -Oc -tWM -w -Q -w-sig- -nlib\.hbmk\win\bcc -Ic:\dev\harbour\include -Iinclude lib\.hbmk\win\bcc\rddsys.c source\client\leto1.c source\client\letomgmn.c source\common\blowfish.c source\common\common_c.c source\common\hbip.c source\common\net.c

Pasha: В Harbour вместо HB_FT_PICTURE определен HB_FT_IMAGE. Сейчас поменяю

alkresin: Уже просто компиляция вернет ошибку (нет функции Some_UDF) Вот пример: Function Main Private x := 2, b, s := "x == 1 .and. f1()" b := &( "{||" + s + "}" ) // Проходит нормально ? eval(b) // Проходит нормально x := 1 ? eval(b) // Ошибка появляется только теперь При строгой проверке (ключ -w3) без "FIELD->" макрокоманда "SET FILTER" не компиляется return nil Ну так можно объявить FIELD ... в начале функции.

AlexMyr: Blob поле создается, но на BLOBIMPORT( nPos, cPixFile ) выдает ошибку Error LETO/0 Operation not supported Called from DBFILEPUT(0) Called from SHOWPIX(20)

alx_on: alkresin пишет: ? eval(b) // Ошибка появляется только теперь Как все сложно :) Не проверил до конца, теперь верю... Хорошо, поставим вопрос по другому: без лето аналогичная ситуация? Да. Зачем перекладывать на сервер проблему кривого написания фильтра? Даже внешне правильно написанный может упасть: Private x := 2, y := 1, b, s := "if(x==2,.T.,y) == .T." Где "y" ошибочно написанное имя поля (цифра 1 для примера падения). Было бы замечательно прикрутить UDF, а со строгой проверкой это невозможно Ну так можно объявить FIELD ... в начале функции В макросах это невозможно (да и не нужно). Но общий стиль написания кода необходимо сохранить (для быстрого понимания - где поле, а где переменная или константа)

alkresin: Хорошо, поставим вопрос по другому: без лето аналогичная ситуация? Да. Нет. Без leto это все отлично выполняется ( при условии наличия в коде клиентской программы соответствующих udf или переменных ). С leto -благодаря parsefilter это ловится и фильтр формируется на стороне клиента - и потому отрабатывает нормально. Без parsefilter сервер бы взял обработку фильтра на себя и при достижении записи с соответствующим значением SOME_FIELD попытался бы выполнить эту UDF, что привело бы ко всяким неприятностям. Зачем перекладывать на сервер проблему кривого написания фильтра? Да не криво написан этот фильтр. Что кривого в том, что вызов UDF стоит не в начале ? Было бы замечательно прикрутить UDF, а со строгой проверкой это невозможно Почему невозможно ? Наоборот - именно благодаря этой строгой проверке фильтр классифицируется как не optimized и благополучно выполняется на стороне клиента.

alx_on: Я говорю о проблеме в целом - невозможности (на текущий момент) написать серверный вариант UDF Это не претензия к лето, такая реализация harbour (где компиляция и выполнение - две совершенно разные вещи). Это не плохо и не хорошо. Так было нужно в некоторых случаях (в зависимости от окружения при запуске). Сейчас нет возможности более тонко контролировать этот процесс (могу ошибаться) Было бы неплохо каким то образом реализовать проверку в более общем варианте, т.е. проверять возможность выполнения на стороне сервера UDF (и не только UDF). Простейший (очень тупой) пример: "if(LEFT(XXX,4)=='1234',.T.,.F.)" Может выполняться на сервере, но не выполняется (повысило бы скорость обработки таблицы в разы при наличии большого кол-ва не попадающих под фильтр записей)

alkresin: Сейчас нет возможности более тонко контролировать этот процесс (могу ошибаться) Было бы неплохо каким то образом реализовать проверку в более общем варианте, т.е. проверять возможность выполнения на стороне сервера UDF (и не только UDF). Вы имеете ввиду возможность просто послать на сервер строку для проверки возможности ее выполнения на нем ? Такой функции действительно нет, но ее очень просто реализовать. Простейший (очень тупой) пример: "if(LEFT(XXX,4)=='1234',.T.,.F.)" Может выполняться на сервере, но не выполняется Почему не выполняется ? Я проверил ( заменив XXX на имя поля ) - выполняется...

alx_on: alkresin пишет: Вы имеете ввиду возможность просто послать на сервер строку для проверки Нет, расширить возможности leto_ParseFilter Я проверил ( заменив XXX на имя поля ) - выполняется... Странно, у меня LETO_ISFLTOPTIM() возвращает .F.

alkresin: Нет, расширить возможности leto_ParseFilter Я понимаю, что эта функция сейчас довольно проста, но все-таки - чего именно в ней не хватает ( кроме обработки field-> ) ? Странно, у меня LETO_ISFLTOPTIM() возвращает .F. Проверьте еще раз, не должно такого быть. Функции left() и if/iif вызываются в server.prg, так что они 100% прилинкованы.

alkresin: Что-то мне последние дни пришло несколько писем с жалобами на то, что leto не компилируется с xHarbour 1.2.1 : Error E2141 source\client\leto1.c 140: Declaration syntax error Warning W8019 source\client\leto1.c 4496: Code has no effect in function letoRegisterRDD Error E2379 source\client\leto1.c 4496: Statement missing ; in function letoRegisterRDD Error E2451 source\client\leto1.c 4500: Undefined symbol 'errCode' in function letoRegisterRDD Error E2451 source\client\leto1.c 4500: Undefined symbol 'letoTable' in function letoRegisterRDD Error E2141 source\client\leto1.c 4527: Declaration syntax error Error E2451 source\client\leto1.c 4820: Undefined symbol 'pModuleSymbols' in function leto1__InitSymbols Error E2451 source\client\leto1.c 4823: Undefined symbol 'hb_letoRddInit' in function _hb_leto_rdd_init_ Кто-нибудь здесь использует xHarbour ?

Pasha: xHarbour почему-то перестал видеть ERRCODE. Я попробую собрать с этой версией, это как раз CVS

Sergey Spirin: Pasha пишет: xHarbour почему-то перестал видеть ERRCODE. Я попробую собрать с этой версией, это как раз CVS По моему, его давно переименовали в HB_ERRCODE. У меня в свое время фаст из-за этого не компилился.

Pasha: Так в разных харборах, старых и новых, может быть по разному: и так typedef unsigned int HB_ERRCODE; и так typedef USHORT HB_ERRCODE; и так typedef USHORT ERRCODE; Может быть использовать LETO_ERRCODE, как в letbdb/source/errint.c ?

Pasha: Сборку для xHb модулей С я поправил, собирается с Harbour SVN, со старым Harbour тоже должно собираться Не будет собираться с xHarbour, когда еще не было hbverbld.h, а он появился года 3 назад Остался вопрос со сборкой server.prg под xHarbour, ругается на строке 111 Если я заменю эту конструкцию, как в комментариях, не пойдет сборка под старым Harbour Я понимаю, что это недостаток препроцессора xHarbour, но как решить этот вопрос пока не придумал

alx_on: alkresin пишет: Проверьте еще раз, не должно такого быть. Функции left() и if/iif вызываются в server.prg, так что они 100% прилинкованы Проверил еще раз, результат: LETO_ISFLTOPTIM= .F. DBFILTER= if(LEFT(DACC,4)=='1208',.T.,.F.) Вот пример (вырезано мое лишнее): REQUEST HB_LANG_RUWIN REQUEST HB_CODEPAGE_RU1251 REQUEST HB_CODEPAGE_RU866 PROCEDURE MAIN LOCAL cPath LOCAL cDrvName LOCAL cFilter request LETO cPath := "//127.0.0.1:2811/" cDrvName := "LETO" SET( _SET_CODEPAGE, "RU1251" ) HB_LANGSELECT( "RUWIN" ) rddSetDefault( cDrvName ) IF leto_Connect( cPath ) == -1 ? "Error init LetoDB", cPath return ENDIF SET( _SET_DATEFORMAT, "DD/MM/YYYY" ) set( _SET_AUTOPEN, .F. ) set( _SET_EPOCH, 1910 ) DbUseArea( .T., cDrvName, cPath+"data/default/journ___.dbf", "JOURN", .T., .F., "RU866" ) ORDLISTADD( cPath+"data/default/idx/journ___.cdx" ) OrdSetFocus( ORDNUMBER("OPDATE") ) cFilter := "if(LEFT(DACC,4)=='1208',.T.,.F.)" DBSETFILTER( &("{||"+cFilter+"}"), cFilter ) ? "LETO_ISFLTOPTIM=", LETO_ISFLTOPTIM() ? "DBFILTER=", DBFILTER() GO TOP RETURN

AlexMyr: alx_on пишет: Вот пример (вырезано мое лишнее): Скрытый текст Тоже бы проверил, но пример не самодостаточный - нет создания базы и наполнения ее данными. Да и базу для проверки уж лучше просто в cPath+"/journ___.dbf"

alkresin: Остался вопрос со сборкой server.prg под xHarbour, ругается на строке 111 Не только. Вот еще мне прислали: Error: Unresolved external '_hb_GetSetStructPtr' referenced from C:\LETODB\OBJ\B32\LETOFUNC.OBJ Если я заменю эту конструкцию, как в комментариях, не пойдет сборка под старым Harbour Я понимаю, что это недостаток препроцессора xHarbour, но как решить этот вопрос пока не придумал А может отказаться от использования этого "hbextcdp.ch" и ограничиться простым перечислением страниц ? Если какая-то окажется не включена - кому надо включит.

Pasha: Надо было снять комментарий с #define HARBOUR_VER_AFTER_101 Но я уже поправил сборку и без такого вмешательства А насчет hbextcdp.ch, может быть в letodb/include приготовить 2 файла: letocdph.ch и letocdpx.ch, и затем средствами make копировать их в letodb/include/hbextcdp.ch, если не существует HB_PATH/include/hbextcdp.ch ? Что-то вроде if not exist ... copy ... ?

alkresin: А насчет hbextcdp.ch, может быть в letodb/include приготовить 2 файла: letocdph.ch и letocdpx.ch, и затем средствами make копировать их в letodb/include/hbextcdp.ch, если не существует HB_PATH/include/hbextcdp.ch ? А как это сделать для hbmk2 ? Можно создать letodb/include/hbextcdp.ch, включив туда какой-то минимальный набор страниц, общий для всех компиляторов/версий и написать в readme, что при отсутствии нужной страницы надо руками дополнить этот файл.

alkresin: Павел, а зачем вот это сделано: 2010-07-09 19:10 UTC+0300 Pavel Tsarenko (tpe2/at/mail.ru) .... * added control SkipBuf value to RecCount limit Это ж лишняя файловая операция, а смысл ? Все равно ведь по eof останов происходит...

Pasha: Если файлы на сервере открываются монопольно, то по reccount ничего не делается, он уже известен. Можно эту проверку оставить только для этого режима, а для shared еене делать. Я добавил проверку, чтобы не выделять лишнюю память без необходимости PS Я сейчас сюда редко заглядываю. Дней через 10 вернусь в рабочий режим

Pasha: Можно ли запустить letodb в windows nt/xp до авторизации пользователя ? Я пробовал в реестре добавлять параметр в раздел: [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunServices] и в раздел [HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows] Параметр: "load"="c:\letodb\letodb.exe" - программы запускаемые до входа пользователя в систему: Но сервер не загружается

Pasha: Помогите разобраться с такой странной ошибкой индексации. xHarbour Открываю файл street.dbf из КЛАДР. Сам кладр можно взять по адресу: http://www.kladr.org/update-kladr-database-2.html Таблица большая, 834457 записей, размер 74MB Кодовая страница программы - RU866 Открываю и индексирую таблицу в режиме readonly: Field Code, Name dbUseArea(.t.,, '\kladr\street',,, .t., 'RU1251') OrdCreate('\kladr\street', 'code', 'CODE', {|| CODE}) OrdCreate('\kladr\street', 'namec', 'SUBSTR(CODE,1,11)+UPPER(NAME)', {|| SUBSTR(CODE,1,11)+UPPER(NAME)}) OrdCreate('\kladr\street', 'nasel', 'SUBSTR(CODE,1,11)', {|| SUBSTR(CODE,1,11)}) OrdCreate('\kladr\street', 'nameg', 'SUBSTR(CODE,1,8)+UPPER(NAME)', {|| SUBSTR(CODE,1,8)+UPPER(NAME)}) OrdCreate('\kladr\street', 'namemp', 'SUBSTR(CODE,1,5)+UPPER(NAME)', {|| SUBSTR(CODE,1,5)+UPPER(NAME)}) клиент сваливается на OrdCreate, причем в разных местах, с ошибкой 9027 Premature Array/Object Release detected, и строка - индексное выражение Почему сваливается именно клиент, непонятно. Сваливается скорее всего на строке 3459 в leto1.c: hb_vmDestroyBlockOrMacro( pKeyExp ); Если убрать кодовую страницу RU1251, то индексация проходит успешно.

alkresin: Сваливается скорее всего на строке 3459 в leto1.c: hb_vmDestroyBlockOrMacro( pKeyExp ); Так скорее всего или точно здесь ? Если здесь, то вопрос в том, почему получается ошибка при выполнении кодоблока. А не может это быть связано с тем, что эта злосчастная RU1251 по-разному называется в Harbour и xHarbour. Если страница с этим именем не прилинкована к клиентскому приложению, то выполнение Upper может вызвать ошибку. И еще: а почему там стоит hb_vmDestroyBlockOrMacro( pKeyExp ) ? При нормальном прохождении SELF_EVALBLOCK() этот pKeyExp освобождается при помощи hb_itemRelease() ...

PSP: Pasha пишет: Можно ли запустить letodb в windows nt/xp до авторизации пользователя ? Я пробовал в реестре добавлять параметр в раздел: [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunServices] А если в [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run] ?

Pasha: PSP пишет: А если в [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run] ? Так эти программы выполняются при входе пользователя, а мне хотелось бы запускать letodb до авторизации пользователя Чтобы просто нажали кнопку включения сервера, и работали

Pasha: alkresin пишет: Так скорее всего или точно здесь ? Если здесь, то вопрос в том, почему получается ошибка при выполнении кодоблока. А не может это быть связано с тем, что эта злосчастная RU1251 по-разному называется в Harbour и xHarbour. Если страница с этим именем не прилинкована к клиентскому приложению, то выполнение Upper может вызвать ошибку. Нет. Я определил место, клиент вываливается при выполнении errCode = SELF_EVALBLOCK( ( AREAP ) pArea, pKeyExp ); С именем кодовой страницы это не связано, я собрал сервер для себя корректно. Да и клиент падает еще до выполнения запроса к серверу. В моем случае - при создании 2-го индекса, т.е. на OrdCreate('\kladr\street', 'namec', 'SUBSTR(CODE,1,11)+UPPER(NAME)', {|| SUBSTR(CODE,1,11)+UPPER(NAME)}) Но в некоторых случаях создавалось 4 индекса, и на 5-м - возникала ошибка Причем я успешно открывал таблицу kladr.dbf, создавал индекс с 32-мя тэгами и условиями for. А при индексации street возникает эта непонятная ошибка Неясно, связано ли это с размерами таблица. Сервер ведь создает индекс, ошибка не на сервере Вот как я открываю kladr: Local aKl := {'kladr',, 0,; {'code', 'SUBSTR(CODE,1,13)'},; {'index', 'INDEX'},; {'coder', 'UPPER(NAME)',,, 'substr(code,3,9)="000000000"'},; {'coderr', 'SUBSTR(CODE,1,2)+UPPER(NAME)',,, 'substr(code,6,6)="000000".and.substr(code,3,3)>"000"'},; {'codera', 'UPPER(NAME)',,, 'substr(code,6,6)="000000".and.substr(code,3,3)>"000"'},; {'codego', 'SUBSTR(CODE,1,2)+UPPER(NAME)',,, 'substr(code,6,3)>"000".and.substr(code,9,3)="000"'},; {'codegra', 'SUBSTR(CODE,1,5)+UPPER(NAME)',,, 'substr(code,6,3)>"000".and.substr(code,9,3)="000"'},; {'codega', 'UPPER(NAME)',,, 'substr(code,6,3)>"000".and.substr(code,9,3)="000"'},; {'codena', 'UPPER(NAME)',,, 'substr(code,9,3)>"000"'},; {'codenr', 'SUBSTR(CODE,1,2)+UPPER(NAME)',,, 'substr(code,9,3)>"000"'},; {'codenra', 'SUBSTR(CODE,1,5)+UPPER(NAME)',,, 'substr(code,9,3)>"000"'},; {'codeng', 'SUBSTR(CODE,1,8)+UPPER(NAME)',,, 'substr(code,9,3)>"000"'},; {'nasel1', 'UPPER(NAME)',,, 'substr(code,3,9)="001000001"'},; {'nasel2', 'UPPER(NAME)',,, 'substr(code,3,9)="000000001"'},; {'city1', 'UPPER(NAME)',,, 'substr(code,6,3)>"000".and.substr(code,9,3)=="000"'},; {'city2', 'UPPER(NAME)',,, 'substr(code,3,6)="001001"'},; {'city3', 'UPPER(NAME)',,, 'substr(code,3,6)="000000"'},; {'city3_2', 'ALLTRIM(UPPER(NAME))+SUBSTR(CODE,1,2)',,, 'substr(code,6,6)="000001"'},; {'regdig', 'SUBSTR(CODE,1,2)',,, 'substr(code,3,9)="000000000"'},; {'name_2', 'ALLTRIM(UPPER(NAME))+SUBSTR(CODE,1,2)'},; {'nasel1_2', 'ALLTRIM(UPPER(NAME))+SUBSTR(CODE,1,2)',,, 'substr(code,3,9)="001000001"'},; {'nasel2_2', 'ALLTRIM(UPPER(NAME))+SUBSTR(CODE,1,2)',,, 'substr(code,3,9)="000000001"'},; {'codera_2', 'ALLTRIM(UPPER(NAME))+SUBSTR(CODE,1,2)',,, 'substr(code,6,6)="000000".and.substr(code,3,3)>"000"'},; {'city_5', 'ALLTRIM(UPPER(NAME))+SUBSTR(CODE,1,5)',,, 'substr(code,9,3)="000"'},; {'ocato', 'ocatd'},; {'gni', 'gninmb'},; {'scode', 'SUBSTR(CODE,1,2)'},; {'tcode', 'SUBSTR(CODE,1,5)'},; {'ncode', 'SUBSTR(CODE,1,8)'},; {'namesocr', 'UPPER(ALLTRIM(name))+" "+UPPER(ALLTRIM(socr))',,, 'substr(code,3,9)="000000000"'},; {'name_s', 'UPPER(ALLTRIM(NAME))+" "+UPPER(ALLTRIM(socr))'},; {'code_all', 'CODE'} } BatOpen({aKl}, ,,,, 'RU1251') В прдмассиве для моей функции открытия индекс описывается параметрами: имя тэга, индексное выражение, условие for (5-й элемент)

PSP: Pasha пишет: а мне хотелось бы запускать letodb до авторизации пользователя А "Назначенные задания" не пробовал?

alkresin: С именем кодовой страницы это не связано, я собрал сервер для себя корректно. Да и клиент падает еще до выполнения запроса к серверу. В моем случае - при создании 2-го индекса В первом индексе у вас ф-и Upper() нет, она появляется как раз во втором. Я так понял, что клиент собран на xHarbour - но в xHarbour сейчас эта кодовая страница называется "RUWIN" ...

Pasha: Дело не в upper и не в xHarbour. Я собираю старым xHarbour, в котором еще есть RU1251. И letodb, и клиентская программа собрана именно с RU1251 К тому же для файла kladr.dbf успешно создается 32 индекса, в которых неоднократно встречается upper. Так что причина ошибки не ясна.

alkresin: Хм.. Странно. Вряд ли это связано с размерами, т.к. клиентской части размеры безразличны, она же непосредственно с файлами дела не имеет. А вы не пробовали все-таки уменьшить этот kladr для эксперимента, ну и программу урезать ?

Pasha: Сейчас убрал из индексного выражения Upper, индексирую по SUBSTR(CODE,1,11)+NAME, и ошибка возникает все равно: Premature String Release detected: '01000001000000100' Called from Substr '01000001000000100' - это значение Code, если сделать go top по первому индексу. Может быть, проблема в использовании hb_stackReturnItem() ? Его использует и Substr в индексном выражении, и SELF_EVALBLOCK Уменьшать не пробовал, это мысль, найду урезанный кладр для 2-х регионов и попробую. Индексацию я вставил в небольшую программу, так что вряд ли дело в программе.

Pasha: Проблема оказалась не в индексации, а в трансляции кодовой страницы Даже если индексация проходит успешно, при обращении к символьному полю возникает ошибка 9009 hb_xrealloc Т.е. в letoGetValue перекодировка выполняется неправильно

Pasha: Да, вопрос решен, вот фикс для leto1.c, со строки 1669: #if defined (__XHARBOUR__) || !defined(__HARBOUR__) || ( (__HARBOUR__ - 0) < 0x020000 ) char * pVal = ( char * ) hb_xgrab( pField->uiLen + 1 ); memcpy( pVal, pArea->pRecord + pArea->pFieldOffset[uiIndex], pField->uiLen ); pVal[ pField->uiLen ] = '\0'; hb_cdpnTranslate( pVal, pArea->area.cdPage, hb_cdp_page, pField->uiLen ); hb_itemPutCL( pItem, pVal, pField->uiLen ); hb_xfree( pVal ); #else char * pVal; HB_SIZE uiKeyLen = pField->uiLen; pVal = hb_cdpnDup( ( const char * ) pArea->pRecord + pArea->pFieldOffset[uiIndex], &uiKeyLen, pArea->area.cdPage, hb_cdp_page ); hb_itemPutCLPtr( pItem, pVal, pField->uiLen ); #endif забросьте пожалуйста на CVS, у меня сейчас нет такой возможности

alkresin: Т.е. если удалить в kladr все записи кроме одной и написать программу: function main REQUEST LETO RDDSETDEFAULT( "LETO" ) use ( "//127.0.0.1:2812/kladr" ) new codepage "RU1251" ? field->SOME_FIELD return Nil то она вылетает ?

alkresin: забросьте пожалуйста на CVS, у меня сейчас нет такой возможности Забросил.

Andrey: Pasha пишет: Так эти программы выполняются при входе пользователя, а мне хотелось бы запускать letodb до авторизации пользователя Чтобы просто нажали кнопку включения сервера, и работали Мне тоже бы хотелось этого ! Какие еще могут быть варианты с запуском сервиса LetoDB ?

sashaBG: Windows XP Pro.. "Start" "Run" пишем < gpedit.msc > Выбираем "Computer Configuration" "Windows Settings" Двойной click на "Scripts(Startup/Shutdown)" Двойной click на "Startup" справо. потом кликаем на "Add" и добавляем скрипт или программу. Закрываем Group Policy editor..

Andrey: sashaBG пишет: Windows XP Pro.. А под 2000 и 2003 ЭТО работать будет ?

sashaBG: Под Windows 7 не работает надо пробовать , у меня есть 2003 на другой машине , вечером попробую .

Pasha: alkresin пишет: Т.е. если удалить в kladr все записи кроме одной и написать программу... Да, у меня ошибка 9009 выскочила, правда почему-то только на 3-й раз А с фиксом все работает. Вроде бы код аналогичный, но тем не менее.. А в Harbour этот пример работает ?

Sergey Spirin: Andrey пишет: Какие еще могут быть варианты с запуском сервиса LetoDB ? Я что-то не понимаю, если он сервис, то какие могут быть проблемы? Идем в службы, находим его и ставим - "тип запуска - Авто". ??

PSP: Запуск сервера - "Панель управления - Назначенные задания"

alkresin: А в Harbour этот пример работает ? У меня kladr сейчас под рукой нет, а качать 74М не хочется.

AlexMyr: Сегодня упал сервер, в letodb_crash.log Breakdown at: 2010.08.06 10:37:04 Unrecoverable error 1010: hb_cdxIndexPageRead: Read index page failed. ------------------------------------------------------------------------ User: 127.0.0.1 GRU VIEWWSGUI.EXE Command: ord;02;513;data;2; Table: \res.dbf Unrecoverable error 9104: hb_cdxIndexFree: index file still locked. Breakdown at: 2010.08.06 10:44:45 Unrecoverable error 6005: Exception error: %s Exception Code:C0000005 Exception Address:00408AC2 EAX:00000000 EBX:00000000 ECX:00000024 EDX:004C0000 ESI:0070FB0C EDI:01050174 EBP:0070FB18 CS:EIP:017F:00408AC2 SS:ESP:0187:0070FAF4 DS:0187 ES:0187 FS:0F9F GS:0000 Flags:00010293 CS:EIP: 83 7B 40 00 0F 84 19 02 00 00 8B 03 50 E8 4C 1A SS:ESP: 00000000 0070FB18 01050174 0070FB0C 01052EA4 00408EBC 00000017 00000000 40E2E3A0 3638004C 30303538 76720031 76207265 392E302E 003B4E3B 00000000 C stack: EIP: EBP: Frame: OldEBP, RetAddr, Params... 00408AC2 0070FB18 3638004C 30303538 76720031 76207265 392E302E 003B4E3B 00000000 004C0CF0 0070FB60 004A4474 ... и letodb.log 08/06/10 10:18:25: Leto DB Server has been started. 08/06/10 10:21:29: Error DBFCDX/1011 Write error: c:\cars\res.dbf (DOS Error 5) 08/06/10 10:26:52: Error DBFCDX/1011 Write error: c:\cars\res.dbf (DOS Error 5) 08/06/10 10:26:52: Error DBFCDX/1011 Write error: c:\cars\res.dbf (DOS Error 5) 08/06/10 10:28:10: Leto DB Server has been started. 08/06/10 10:32:18: Leto DB Server has been started. 08/06/10 10:38:07: Leto DB Server has been started. 08/06/10 10:44:00: Error DBFCDX/1011 Write error: c:\cars\res.dbf (DOS Error 5) 08/06/10 10:44:45: Error DBFCDX/1011 Write error: c:\cars\res.dbf (DOS Error 5) 08/06/10 10:44:45: Error DBFCDX/1011 Write error: c:\cars\res.dbf (DOS Error 5) 08/06/10 10:48:42: Leto DB Server has been started. База res размером 42 Мб, записей 1060560. Работает програма с декабря 2009 года. Только один компьютер собирает информацию и записывает данные в базу через leto_BeginTransaction() ... leto_CommitTransaction(), 3-4 компа только читают. После падения потерялись в базе за вчерашний день больше половины информации за сегодняший почти вся. Что могло произойти?

Pasha: Ошибка возникает при выполнении команды ord;02, т.е при вызове OrdKeyNo Возможно, произошло разрушение индексного файла Вы открываете БД в режиме shared или монопольно ?

AlexMyr: Share_tables = 1

Pasha: AlexMyr пишет: Share_tables = 1 А зачем ? Если сервер открывает БД монопольно, он работает намного лучше Возможно, в процессе совместной работы letodb и еще какой-то программы и произошло нарушение индекса.

Pasha: После выполнения OrdListAdd текущая запись становится не первая по индексу, а запись с номером один, на которую таблица позиционируется после открытия без индекса. Для исправления несовместимости предпочтительнее будет изменить протокол, в результат команды open;02 добавить leto_rec, и на клиенте отрабатывать ParseRec Хотя можно и с клиента после открытия индекса делать gotop прямо в функции letoOrderListAdd Как сделать ?

alkresin: AlexMyr пишет: Unrecoverable error 1010: hb_cdxIndexPageRead: Read index page failed. Да, это повреждение индекса. Оно может произойти или из-за какой-либо ошибки в dbfcdx, или, поскольку у вас используется Share_tables = 1, из-за аварийного завершения клиентской программы, работающей параллельно с leto. А вот в пропажу информации из БД не верится. При Share_tables = 1 letodb открывает таблицу в shared режиме ( если она в программе открывается как shared - а раз ту таблицу читают с других компьютеров, это, наверное, так и есть ). DBFCDX в shared режиме, естественно, не использует буферы и записывает каждое изменение на диск, чтобы параллельно работающие программы его сразу видели. Возможно, переиндексировав файл, вы найдете все "потерянные" записи.

alkresin: Pasha пишет: Для исправления несовместимости предпочтительнее будет изменить протокол, в результат команды open;02 добавить leto_rec, и на клиенте отрабатывать ParseRec Хотя можно и с клиента после открытия индекса делать gotop прямо в функции letoOrderListAdd Первый вариант, конечно, предпочтительнее. Меня лично не пугает в данном случае изменение протокола, поскольку оно не должно привести к нарушению работы программ в случае, когда клиент и сервер откомпилированы разными версиями. Но тут есть такой момент, что текущий индекс и текущая запись изменяются только если открываемый индекс - первый. А если второй, третий и т.д., то текущий индекс и, соответственно, запись, остаются прежними - надо это учесть.

AlexMyr: alkresin пишет: Да, это повреждение индекса. Оно может произойти или из-за какой-либо ошибки в dbfcdx, или, поскольку у вас используется Share_tables = 1, из-за аварийного завершения клиентской программы, работающей параллельно с leto. А вот в пропажу информации из БД не верится. При Share_tables = 1 letodb открывает таблицу в shared режиме ( если она в программе открывается как shared - а раз ту таблицу читают с других компьютеров, это, наверное, так и есть ). DBFCDX в shared режиме, естественно, не использует буферы и записывает каждое изменение на диск, чтобы параллельно работающие программы его сразу видели. Возможно, переиндексировав файл, вы найдете все "потерянные" записи. Да я сразу всех остановил (пользователей, сервер), индекс удалил, запустился, индекс создался, но данных нет (смотрел саму базу без индекса - тоже данных нет). Может дело все в том, что у меня сервер собран еще второго февраля, а клиент собран в мае (хотя до того дня все работало)?

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

alkresin: 3-4 компа только читают. А эти 3-4 компа через letodb работают ? Я это к тому, что если они работают параллельно, через dbfcdx ( иначе зачем share_tables=1 ? ) и "видят" каждое новое изменение - значит, это каждое изменение записывается на диск ... Есть сейчас в реализации транзакций один момент, который меня беспокоит - по ее завершении не происходит автоматический commit, а если он находится между leto_BeginTransaction() и leto_CommitTransaction(), то он не передается на сервер. Думаю, что в shared режиме добавляемые записи и без commit должны писаться на диск ( сейчас у себя сделал маленький тест - вроде так и есть ), но все равно commit внутри транзакции сделать надо.

AlexMyr: alkresin пишет: А диск на потерянные кластеры проверяли ? Проверю. alkresin пишет: А эти 3-4 компа через letodb работают ? Я это к тому, что если они работают параллельно, через dbfcdx ( иначе зачем share_tables=1 ? ) и "видят" каждое новое изменение - значит, это каждое изменение записывается на диск ... Да, через letodb, а с share_tables игрался когда тестировал, то так и оставил, не менял больше. Еще открывал Dos Navigatorom по F3 (на компе где leto запущено и база лежит), но сначала работы програмы такого не было.

Pasha: AlexMyr пишет: у меня сервер собран еще второго февраля, а клиент собран в мае Лучше пересобрать и сервер, и клиент. За последнее время было много существенных изменений, в том числе исправлялись ошибки

AlexMyr: Буду пересобирать, но уже в сентябре - ухожу в отпуск

Pasha: Сбросил кое-какие изменения: Функция Leto_Memoread() - Отключил проверку SkipBuf для shared режима; - Позиционирование на первую запись при открытии индекса; - Обьявление кодовых страниц перенес в отдельный файл - Протокол для открытия индекса изменился, но, поскольку содержимое записи добавлено в конец пакета, клиент можно не пересобирать Но, если клиент пересобран, надо собрать и сервер.

Pasha: Для вызова с клиента функций на сервере предлагается такая схема: Сервер собирается вместе с модулем udf.prg, в который разработчик по желанию сможет добавлять свои функции. Первый параметр, который получает такая функция - это nUserStru. На сервере добавляется функция Leto_Alias(nUserStru, cClientAlias) --> cRealAlias, которая возвращает реальный алиас по клиентскому, для доступа к таблицам БД. Эта функция уже написана. На клиенте добавляется функция Leto_Udf(<cFuncName>, Param1, ...). Серверу передается команда usr;01;cFuncName;cParams Параметры формируются с помощью HB_Serialize. На сервере параметры обрабатываются с помощью hb_DeSerialize, функция выполняется, результат возвращается опять таки через HB_Serialize - hb_DeSerialize Поскольку для xHarbour HB_Serialize сделана на prg-уровне, прийдется написать обертку, что-то вроде leto_Serialize Недостаток этого способа (пока) - то, что udf-функция будет выполняться в основном потоке, но, думаю, он будет устранен. Некорректная функция к тому же может привести к падению сервера, но это уже будет проблема разработчика такой функции.

Pasha: В конце концов реализовал (пока) такую схему: На клиенте вызывается функция: leto_udf(cServerName+cFunction, cParam) пример: leto_udf('//127.0.0.1:2812/leto_alias', 'employee') на сервере вызывается функция cFunction с параметрами nUserStru и cParam ее результат (пока только символьная строка) возвращается клиенту В дальнейшем планирую реализовать произвольное число параметров любых типов На сервере для реализации пользовательских функций загружается файл letoudf.hrb, в котором пользователь и делает свои функции В связи с этим у меня вопрос: как загружать hrb на старом харборе ? Сейчас я сделал так в server.prg: #ifndef __XHARBOUR__ #include "hbhrb.ch" #endif ... IF File( "letoudf.hrb" ) #ifndef __XHARBOUR__ hb_HrbLoad(HB_HRB_BIND_DEFAULT, "letoudf.hrb" ) #else __hrbLoad( "letoudf.hrb" ) #endif WrLog( "letoudf.hrb has been loaded." ) ENDIF будут ли эти операторы компилироваться старым Harbour ? В дальнейшем еще планирую для udf-функций дать возможность возвращать клиенту содержимое изменившихся рабочих областей, т.е. leto_rec Скажем, функция-триггер добавила запись, и вернула ее клиенту

Pasha: Пример udf-функции, которая вызывается с клиента, добавляет запись на сервере, заполняет ключевое поле по индексу cOrder, и возвращает полученную запись: Function Leto_AppKey(nUserStru, cAlias, cOrder) Local cRealAlias := Leto_Alias(nUserStru, cAlias) Local cField, cKey := "", nKey if ! Empty(cRealAlias) dbSelectArea(cRealAlias) OrdSetFocus(cOrder) cField := IndexKey() dbGoBottom() cKey := FieldGet(FieldPos(cField)) nKey := Val(cKey) dbAppend() FieldPut(FieldPos(cField), StrZero(nKey+1, len(cKey)) ) dbCommit() // Еще не реализовано: кроме возврата результата функции, на клиенте еще будет получена текущая запись в рабочей области cAlias //leto_udfrec(nUserStru, cRealAlias) endif Return cKey Какие будут мнения, сомнения, предложения, замечания ?

alkresin: будут ли эти операторы компилироваться старым Harbour ? Какие именно операторы ? Ф-я hb_HrbLoad(() в старом Harbour есть. А вот hbhrb.ch - нет, поэтому у меня оно не компилируется.

alkresin: Обнаружил один неприятный момент - dbusearea() перестала возвращать neterr(), когда это надо, а вместо этого выдает стандартный error. Раньше в letoOpen() ( leto1.c ) стояла проверка кода возврата от сервера, и если это -004, то предпринимались соответствующие действия. Теперь этот код закомментирован и вместо него используется ф-я leto_checkerror(), где эта проверка не производится. Если нет возражений, я сделаю как было.

Pasha: А у функции hb_hrbLoad 2 параметра, nOption и имя файла ? Уберите hbhrb.ch , и поставьте #define HB_HRB_BIND_DEFAULT 0x0

Pasha: alkresin пишет: Если нет возражений, я сделаю как было. Конечно делайте Еще надо заменить hb_retcAdopt на hb_retc_buffer в letofunc.c Этой функции сейчас в Harbour нет

alkresin: Pasha пишет: А у функции hb_hrbLoad 2 параметра, nOption и имя файла ? Нет, только имя файла

Pasha: alkresin пишет: Pasha пишет: цитата: А у функции hb_hrbLoad 2 параметра, nOption и имя файла ? Нет, только имя файла Плохо. У этой функции в разных версиях получаются разные правила вызова. В старом Harbour есть еще функция __hrbLoad, которой нет в новом Можно ли проверить, есть ли символ __hrbLoad, и, если есть, вызывать вместо функции hb_hrbLoad функцию __hrbLoad, но не напрямую, а через макроподстановку ? Вроде: #ifndef __XHARBOUR__ if SYMEXIST("__HRBLOAD") // как проверить ? &("__HrbLoad(0,'letoudf.grb')") else hb_HrbLoad(0, "letoudf.grb") endif #else ...

alkresin: Изначально проблема состоит в том, что в xHarbour и в Harbour 1.0 препроцессор работает не вполне корректно, так ведь ? Тогда можно перенести вызов hb_HrbLoad() на С уровень.

Pasha: Остался вопрос по корректному закрытию сервера при выключении компьютера. Как можно под windows, терминал gtgui, перехватить событие WM_ENDSESSION ? Ведь окно программы не создается. Кстати, при перезагрузке/выключении компьютера функция exit function не вызывается

PSP: А если запускать LetoDB как системную службу?

AlexMyr: PSP пишет: А если запускать LetoDB как системную службу? на 98 винде где она эта служба?

PSP: AlexMyr пишет: на 98 винде где она эта служба? Ну да... Просто я уже забыл про нее... :)

Pasha: Дело не в версии win, а в том, что letodb не служба, и средствами harbour ее сделать как служба сейчас не получится Так что вопрос, где ловить событие, остается

alkresin: Остался вопрос по корректному закрытию сервера при выключении компьютера. Как можно под windows, терминал gtgui, перехватить событие WM_ENDSESSION ? Ведь окно программы не создается. Варианты такие: 1) создать окно для сервера и обрабатывать сообщения, реализовав все это на С уровне без использования харборовских GUI библиотек. В принципе, это очень просто, вопрос в том, как это скажется на производительности - это можно проверить экспериментальным путем. 2) По примеру ранее обсуждавшейся утилиты написать маленькую утилитку с окном, которое будет ловить WM_ENDSESSION и корректно закрывать сервер. Правда, это может и не сработать - а вдруг Windows убьет letodb раньше, чем пошлет сообщение для этой утилиты. 3) Выяснить, есть ли в Windows средства поймать и обработать момент закрытия процесса, не имеющего окна. 1-й представляется наиболее универсальным ( для всех версий Windows ) и простым.

alkresin: To Pasha: По поводу последних изменений: было бы хорошо перенести эти новые элементы, возвращаемые при открытии таблицы в конец - так можно было бы избежать проблем с версиями клиента и сервера.

alkresin: И еще по поводу последних изменений - там закралась какая-то ошибка. Мне прислали вот такой тест: FUNCTION Main REQUEST LETO #include 'inkey.ch' LOCAL cPath := '//127.0.0.1:2812/' rddSetDefault( "LETO" ) CriaDB( cPath ) dbUseArea( .T. , 'LETO', cPath + 'test', 'pa', .F. , .F. , ) dbAppend() REPLACE mercadoria WITH 'teste 1' dbAppend() REPLACE mercadoria WITH 'teste 2' dbAppend() REPLACE mercadoria WITH 'teste 3' dbgotop() obro := tbrowsedb( 05, 1, MaxRow() - 7, MaxCol() - 1 ) ocol01 := tbcolumnnew( "Produto" , { ||pa -> mercadoria } ) obro:addcolumn( ocol01 ) WHILE .T. WHILE ( !obro:stabilize() ) ; ENDDO // msginfo( str(recno())) tecla := Inkey( 0 ) TestaTecla( tecla, obro ) IF tecla = K_ESC EXIT ENDIF ENDDO RETURN Nil FUNCTION CriaDB( cPath ) IF PCount() = 0 dbCreate( "test.dbf", { { "mercadoria","C",30,0 } }, 'DBFCDX' ) ELSE dbCreate( cPath + "test.dbf", { { "mercadoria","C",30,0 } }, 'LETO' ) ENDIF //***************************** FUNCTION TestaTecla( tecla, obj ) //***************************** DO CASE CASE tecla = K_UP ; obj:up() CASE tecla = K_DOWN ; obj:down() CASE tecla = K_LEFT ; obj:Left() CASE tecla = K_CTRL_LEFT ; obj:panleft() CASE tecla = K_RIGHT ; obj:Right() CASE tecla = K_CTRL_RIGHT ; obj:panright() CASE tecla = K_PGUP ; obj:pageup() CASE tecla = K_CTRL_PGUP ; obj:gotop() CASE tecla = K_PGDN ; obj:pagedown() CASE tecla = K_CTRL_PGDN ; obj:gobottom() CASE tecla = K_HOME ; obj:home() CASE tecla = K_CTRL_HOME ; obj:panhome() CASE tecla = K_END ; obj:end() CASE tecla = K_CTRL_END ; obj:panend() CASE tecla = K_MWFORWARD ; obj:up() CASE tecla = K_MWBACKWARD ; obj:down() ENDCASE RETURN nil При прохождении вверх/вниз в browse появляются лишние строки - что-то не то с eof()

Pasha: Я тоже пытался добиться от Itamar M. Lins Jr. Lins пример, но мне это не удалось. Наконец он его дал Баг связан с буферизацией в skip при смене направления перемещения. Поскольку класс tbrowse в harbour и xharbour разный, в первом баг проявляется, а во втором - нет. Вот как он проявляется, если в примере добавлять не 3 записи, а 2: dbUseArea( .T. , 'LETO', cPath + 'test', 'pa', .F. , .F. , ) dbAppend() REPLACE mercadoria WITH 'teste 1' dbAppend() REPLACE mercadoria WITH 'teste 2' dbgotop() Skip 1 // стабилизация tbrowse - идем вниз ? "skip 1", RecNo(), bof(), eof() Skip 1 // стабилизация tbrowse - идем вниз ? "skip 1", RecNo(), bof(), eof() Skip -1 // стабилизация tbrowse - уперлись в eof, возвращаемся ? "skip -1", RecNo(), bof(), eof() Skip -1 // стабилизация tbrowse - уперлись в eof, возвращаемся ? "skip -1", RecNo(), bof(), eof() skip -1 // пользователь нажал K_UP ? "skip -1", RecNo(), bof(), eof() Skip 1 // пользователь нажал K_DOWN ? "skip 1", RecNo(), bof(), eof() // здесь баг: после skip должна быть запись № 2, а остается запись № 1 Skip 1 ? "skip 1", RecNo(), bof(), eof() // дальше - последствия этого бага wait как исправить баг, я пока не увидел.

alx_on: многопоточность Примечание: Для использования таблиц в exclusive режиме приходится использовать hb_rddDetachArea и hb_rddRequestArea (при этом замедление работы одного соединения (в худшем варианте), примерно, 15%) Но (я надеюсь, пока не пробовал) в целом отзывчивость системы на множестве соединений должна быть лучше, чем раньше 0 - главный поток а) как и ранее отрабатывает новые соединения б) часть команд в) для (уже установленных) соединений принимает команды в буфер если есть свободный поток - вызывает ThreadCondUnlock для него 1 - вторичный поток а) только открывает и закрывает таблицы (дабы не городить огород, например, при одновременном открытии в двух потоках одной и той же таблицы) после открытия таблицы hb_rddDetachArea перед закрытием таблицы hb_rddRequestArea б) если есть новая команда (открытия закрытия) - снова отрабатывает если нет - ThreadCondWait 2 и далее (по ядрам или настраиваемо в ini) а) собственно отработка команд (кроме команд для потока 1) перед работой с таблицой hb_rddRequestArea после hb_rddDetachArea (один момент - ожидание другого потока, если таблица уже в работе) б) если есть новая команда - снова отрабатывает если нет - ThreadCondWait Какие замечания к схеме?

Pasha: letodb работал на сервере win2k. Внезапно он перестал запускаться. Причем, до сбоя компьютер не перегружался более месяца, и letodb также работал без останова (видно по логу) больше месяца. Теперь по логу видно, что letodb стартует и сразу же останавливается. Раскопки показали, что завершение происходит на вызове: if( ( hSocketMain = hb_ipServer( iServerPort, NULL, 10 ) ) == ( HB_SOCKET_T ) -1 ) return; Перед return я поставил вызов hb_iperrorcode(), он возвращает код ошибки 0x2736. Где можно глянуть, что это за ошибка ? Почему не выполняется hb_ipServer - совершенно непонятно. Пришлось перенести letodb на другой компьютер с winxp. Но бывший сервер не коннектится с новым сервером, т.е. не работает и как клиент. Это еще не все. В этой же сети есть станция с win98, которая полтора месяца назад вдруг ни с того ни с сего перестала коннектиться с letodb. Я писал об этом. Тогда на ней пришлось переустановить win98. Так вот, теперь эта станция не коннектится с letodb на новом сервере. Повторять переустановку ОС я не стал, пришлось настроить запуск letodb в режиме Share_Tables=1, и с этой станции работать с БД через dbfcdx. Такие вот пироги с котятами. Самое неприятное, что такие сбои происходят неожиданно, после продолжительного периода стабильной работы без единого сбоя Особенность этой сети то, что у сетевушек настроено два ip адреса, вторая подсеть - для доступа в инет. Но изначально letodb работал, работать он прекращает внезапно и навсегда, по неизвестной причине.

Pasha: Ошибку я нашел: #define WSAENOTSOCK (WSABASEERR+38) Вот пишут: http://www.wasm.ru/forum/viewtopic.php?id=18803 Мегажесть :) - оказывается стек, не выровненный на 4 байта при вызове socket вызывает такую лажу Я на такую лажу натыкался c файлами работал)))) Стек приходится по всей программе выравнивать, иначе любая функция винды тожет глюкнуть. Притом происходить это будет через раз, один раз откопмилил не сработала, второй раз откомпилил, пашет. Т.е. ты можешь даже не заметить проблему...

AlexMyr: Та же ситуация, но я так и не смог запустить letodb на windows server 2003 r2, в логе сразу start stop, и как клиент 2003 не захотел работать. HBNETIO тоже не стартует на 2003. Видно блокируются порты, не стал разбираться тк 2003 загружен работой и перезагружать его каждые 5 минут после изменения параметров не хочется и letodb работает на 98 винде дальше.

Pasha: Я некорректно написал. Я нашел пока только код ошибки, а как исправить ситуацию - нет

Pasha: У компилятотра bcc32 по умолчанию используется опция -a4, т.е. выравнивание на 4 байта. Значит, дело не в выравнивании

AlexMyr: Только что пересобрал с помощью mingw harbour и letodb. Letodb запустился на windows server 2003 r2 и продолжил работать . Завтра потестирую работу на базах. И hbnetio тоже заработал. Вот.

Pasha: Может быть, проблема в борландовской wsock32.lib ? В ней нет выравнивания на 4 байта ?

alkresin: Pasha пишет: Может быть, проблема в борландовской wsock32.lib ? В ней нет выравнивания на 4 байта ? Или, может, bcc старый, не учитывает какие-то фишки 2003 ... У меня letodb (откомпилированный с bcc 5.5) эксплуатируется, кроме линуксовых, еще на паре компьютеров с XP - никогда таких вещей не было.

Pasha: alkresin пишет: Или, может, bcc старый, не учитывает какие-то фишки 2003 ... У меня letodb (откомпилированный с bcc 5.5) эксплуатируется, кроме линуксовых, еще на паре компьютеров с XP - никогда таких вещей не было. У меня ошибка возникает на 2000 server и на win98 Гугль на "socket error WSAENOTSOCK" выдает большое количество ссылок, но в чем проблема в нашем случае - непонятно Я добавил диагностику ошибок, связанных с сокетами

Pasha: AlexMyr пишет: Только что пересобрал с помощью mingw harbour и letodb. Letodb запустился на windows server 2003 r2 и продолжил работать Алексей, то есть сейчас у вас letodb-bcc не запускается, а letodb-mingw запускается ? Можете проверить, попробовать запустить letodb-bcc ?

AlexMyr: Pasha пишет: Алексей, то есть сейчас у вас letodb-bcc не запускается, а letodb-mingw запускается ? Можете проверить, попробовать запустить letodb-bcc ? Ничего не понимаю , проверил - запускается и letodb-bcc и letodb-mingw. Нашел letodb собраный еще в ноябре 2009 - тоже запустился. Может после запуска letodb-mingw что-то изменилось? До этого даже в выходной вышел чтобы никто не мешал - letodb не запускался, плюнул и оставил работать на 98.

Pasha: AlexMyr пишет: Ничего не понимаю Наверное, что-то изменилось в настройках ОС

Pasha: Вот нашел какую-то утилиту, которая вроде бы фиксит проблему с ошибкой 10038: http://www.subnixus.com/error-codes/error-10038.html На страничке про сокеты ничего нет, но в гугле вот что видно: How To Fix Error 10038 Problems :: Windows Help - [ Перевести эту страницу ]A Windows sockets application may return error 10038 (WSAENOTSOCK) in response to various socket calls. The Windows NT error "OBJECT_TYPE_MISMATCH" is ... www.subnixus.com/error.../error-10038.html - Сохраненная копия Если это так, то что-то правится в реестре Как опробую, отпишу результат

Pasha: Ага, не опробую Это чудо оказывается платное

Pasha: Вот есть еще что-то, но только для winxp: http://www.snapfiles.com/get/winsockxpfix.html ссылка через: http://www.firebirdfaq.org/faq4/ Поскольку есть такие тулзы, возможно, это не програмная ошибка letodb, а системная

PSP: По поводу бага с появлением в бровсе лишних записей. С предпоследней и последней сборкой LetoDB я тоже налетел на этот баг. Откатился к сборке от 30.07.10 (самое свежее, что сохранилось), - баг исчез. Harbour не менялся 2.0.0. Вот...

alkresin: PSP пишет: По поводу бага с появлением в бровсе лишних записей. С предпоследней и последней сборкой LetoDB я тоже налетел на этот баг. Теперь ясно, в чем дело - это я напортачил. Исправлено.

PSP: Да, все Ok. :)

Pasha: Сейчас мне приходится использовать расшаренный ресурс на сервере, хотя бы для того, чтобы с него запускать бинарники. Хочется добавить еще одну файловую функцию, которая возвращала бы информацию о файле: размер, дату и время создания и пр. Тогда можно было бы написать утилиту, которая проверяла и скачивала бы с сервера обновления бинарников посредством leto_memoread. Таким образом можно было бы полностью отказаться от использования расшаренного ресурса: 1) Метаданные считываются посредством leto_memoread 2) Документы office копируются также с помощью leto_memoread во временный каталог, и открываются офисным приложением 3) Обновления также скачиваются с сервера Собственно, такую фунцию можно реализовать с помощью механизма udf, но, мне кажется, она будет нелишней в ядре leto Какие будут мнения ?

AlexMyr: Тоже думаю как записать ini-файл на сервер?

Pasha: AlexMyr пишет: Тоже думаю как записать ini-файл на сервер? Можно сделать leto_memowrite, можно на сервере подключить udf-функцию

PSP: Pasha пишет: Хочется добавить еще одну файловую функцию, которая возвращала бы информацию о файле: размер, дату и время создания и пр. Какие будут мнения ? Поддерживаю.

alkresin: Pasha пишет: Хочется добавить еще одну файловую функцию, которая возвращала бы информацию о файле: размер, дату и время создания и пр. Тогда можно было бы написать утилиту, которая проверяла и скачивала бы с сервера обновления бинарников посредством leto_memoread. Такой функции и leto_memoread недостаточно для реализации обновления клиентской программы. Я думал об этом пару лет назад и тоже хотел сначала сделать это через letodb. Но проблема в том, что информация о файлах, необходимых для работы клиента ( бинарник, ini, шаблоны отчетов и пр. ) должна лежать на сервере. Клиент может и не знать, какие файлы нужны - при первоначальной установке, или если вы добавили новые файлы ... Т.е. на сервере должен быть, скажем так, ini - файл со списком каталогов и файлов для каждого клиентского модуля, и сервер должен читать этот файл при запуске, а при запросе со стороны клиента отдавать ему список нужных файлов с датой/временем создания, чтобы клиентская утилита могла определить, какие файлы ей затребовать. Словом, на сервер возлагается ряд нетипичных для letodb задач, поэтому я и написал для этого другую серверную программу, которая все это делает. В принципе, я могу ее выложить куда-нибудь, только нету времени потом на вопросы по ней отвечать :)

Andrey: Pasha пишет: Тогда можно было бы написать утилиту, которая проверяла и скачивала бы с сервера обновления бинарников посредством leto_memoread. Pasha пишет: Собственно, такую фунцию можно реализовать с помощью механизма udf, но, мне кажется, она будет нелишней в ядре leto Какие будут мнения ? Полностью поддерживаю ! Эта просто НУЖНАЯ ВЕЩЬ для разработчика !!!

Andrey: alkresin пишет: Словом, на сервер возлагается ряд нетипичных для letodb задач, поэтому я и написал для этого другую серверную программу, которая все это делает. В принципе, я могу ее выложить куда-нибудь, только нету времени потом на вопросы по ней отвечать :) Я и раньше просил про такую программу, но что-то вы не ответили ! Было бы неплохо всем желающим посмотреть, а все остальное потом ....

alkresin: Andrey пишет: Я и раньше просил про такую программу, но что-то вы не ответили ! Было бы неплохо всем желающим посмотреть, а все остальное потом .... http://kresin.belgorod.su/down/letofc.zip В samples - собственно клиентская утилита renew.prg, которая забирает с сервера нужные файлы, bld.bat - чтоб ее построить, dogovor.bat - пример использования. bin/lfcmod.ini - ini - файл на стороне сервера со списками файлов. У меня это работает под одной из старых версий Harbour, какой именно - не помню, компилировал последний раз пару лет назад. Компиляцию с другими версиями не гарантирую, т.к. не озадачивал себя этой проблемой.

Andrey: alkresin пишет: alkresin Спасибо большое !

Pasha: alkresin пишет: Такой функции и leto_memoread недостаточно для реализации обновления клиентской программы. Я думал об этом пару лет назад и тоже хотел сначала сделать это через letodb. Но проблема в том, что информация о файлах, необходимых для работы клиента ( бинарник, ini, шаблоны отчетов и пр. ) должна лежать на сервере. Клиент может и не знать, какие файлы нужны - при первоначальной установке, или если вы добавили новые файлы ... Т.е. на сервере должен быть, скажем так, ini - файл со списком каталогов и файлов для каждого клиентского модуля, и сервер должен читать этот файл при запуске, а при запросе со стороны клиента отдавать ему список нужных файлов с датой/временем создания, чтобы клиентская утилита могла определить, какие файлы ей затребовать. Словом, на сервер возлагается ряд нетипичных для letodb задач, поэтому я и написал для этого другую серверную программу, которая все это делает. Тогда лучше хранить информацию о бинарниках: размер, дату создания, может быть версию, или хэш-значение, или crc32 - в дбф. На сервере пусть запускается утилитка, которая обновляет эту информацию. На клиенте другая утилитка пусть сканирует этот дбф, и, при необходимости, обновляет у себя бинарники посредством leto_memoread. Тогда эту схему можно реализовать через letodb

Pasha: Как передавать от сервера клиенту большие пакеты ? Большие пакеты разбиваются на несколько маленьких, а в leto1.c - leto_Recv есть проверка: if( ( lLen > 0 && lLen+iLenLen+1 <= ptr-szBuffer ) || ( iLenLen >= 10 && *(ptr-1) == '\n' && *(ptr-2) == '\r' ) ) break; При приеме может возникнуть случай, когда 1-й байт пакета, на который дробится большой пакет, больше 10, а два последних - перевод строки. При возникновении такой ситуации передача прерывается. Как раз я наткнулся на такой случай в leto_Memoread. Александр, я вам отправил этот пример. Но как решить этот вопрос в общем случае ? Такая ситуация может возникнуть и при чтении memo-поля

Pasha: Уже разобрался, вопрос снят

Pasha: Добавил поддержку для операции letoTrans. Теперь команды COPY TO/APPEND FROM будут выполняться сервером. Поскольку в стандартных функциях __dbTrans(), __dbCopy(), __dbApp() условие для FOR/WHILE передается как блок кода, а для выполнения на сервере необходимо строковое представление, добавил в tests пример с аналогами этих функций.

Pasha: LETO IndexExt(), OrdBagExt() возвращает имя ".CDX" на верхнем регистре. DBFCDX - на нижнем. Думаю, стоит использовать нижний регистр и для LETO, тем более для unix регистр существенен. Изменить ? Ни у кого проблем с совместимостью с прежними версиями не возникнет ?

AlexMyr: Pasha пишет: Думаю, стоит использовать нижний регистр и для LETO, тем более для unix регистр существенен. Изменить ? +1

PSP: В letodb.ini есть параметр Lower_Path. Может нужно его установку учесть?

AlexMyr: В readme_rus написано: Lower_Path = 0 - если 1, преобразовать все пути к нижнему регистру; т.е. распространяется только на пути.

Pasha: Судя по сырцам, это установка только для сервера, она влияет только на SET( _SET_FILECASE, 1 ) SET( _SET_DIRCASE, 1 ) _SET_FILECASE должен по идее действовать на файловые функции харбора. Но я смотрю, индекс все равно создается с расширением на верхнем регистре, по крайней мере для xHarbour (bagname я формирую на клиенте с использованием IndexBagExt() и передаю на сервер) Так что думаю, на клиенте надо возвращать расширение все-таки на нижнем регистре, хотя бы для совместимости с DBFCDX Еще заодно надо поменять RDDI_ORDBAGEXT, заодно и RDDI_TABLEEXT, да и прочие *EXT - надо возвращать расширение с точкой.

Дигидроген монооксид: Ставлю последний harbour из SVN, последние HwGUI и LetoDB из CVS. Успешно собираю сервер. Собираю Manager. Но при попытке его запустить, он только записывает в лог Application Internal Error - (null) Terminated at: 2010.10.13 16:37:04 Unrecoverable error 9000: Module 'manage.prg' was compiled with unsupported PCODE version 0.3. Please recompile. ------------------------------------------------ ЧЯДНТ?

Pasha: Дигидроген монооксид пишет: ЧЯДНТ? Возможно, letodb manager и hwgui собраны разными версиями harbour, об этом свидетельствует сообщение о неподдерживаемой версии пи-кода Лучше пересобрать также и hwgui

dimao: вот скачал последний тарбол и собрал последним Харбором. скомпилил тест - выполнился. пытаюсь сделать на базе теста свой пример - вылетает. Нашел ошибку - опять вылетает, но по "Error LETO/1 Open error: //127.0.0.1:2812/temp/Nakl1". смотрю процессы - нету letodb! запускаю сервер - лог пополняется сообщением, что он server already running. на предложение остановиться - никакой реакции! Некоторое время назад тут было сообщение от мистера Snake : http://clipper.borda.ru/?1-4-200-00000322-000-20-0#018.001, на которое не последовало реакции (ну или я не увидел). ТАк и должно быть?

Pasha: Проблема у snake была 2 года назад, и проблема непонятная. Сервер letodb падает, но падает как-то непонятно, не совсем, так что потом не запускается ? Прежде всего надо выяснить, почему он упал. Сервер не должен падать, даже если с ним некорректно работает клиент. Что привело к падению сервера ? Какие ошибки в клиентской программе ? В логе что-нибудь есть ?

dimao: в логе ничего нет, кроме сообщений о старте и том, что он уже выполняется. ps не выводит в списке процессов. воспроизвести ситуацию не могу пока, так как на радостях пользовал его по разному. так как за долгие годы подзабыл синтаксис - много раз вылетали проги. я не сразу насторожился при появлении Error LETO/1. в сях и линуксях я не силен, не могу посмотреть, как он определяет наличие выполняющегося себя. ладно, если еще появится трабла - попытаюсь сделать инструкцию по ее повторению.

dimao: ну вот опять! со вчерашнего дня оставил сервер. Сегодня смотрю - нет в процессах, логов нет. на предложение запустить - говорит, что уже работает. на предложение остановить - никакой реакции. Где смотреть? как он видит, что уже запущен?

Pasha: Мне с одного клиента надо коннектиться ко многим серверам letodb, в связи с чем ограничение MAX_CONNECTIONS_NUMBER хотелось бы снять. Для этого надо динамически выделять память для letoConnPool. Это лучше всего делать вызовом hb_xrealloc. Но эта функция может переместить область памяти в другое место, и тогда pConnection в AREASTRU будет ссылаться на невыделенную память, что нехорошо. В связи с этим есть предложение: вместо ссылки в AREASTRU хранить индекс uiConnection в letoConnPool. Кстати, подобный возможный баг есть в harbour/contrib/rddsql: если память под s_pConnection перевыделяется, ссылка на pConnection в _SQLBASEAREA может вызвать gpf

Andrey: Pasha пишет: Мне с одного клиента надо коннектиться ко многим серверам letodb А разве так можно ? Что за задачи решаются таким образом ? Поделитесь пожалуйста опытом !

Pasha: Да ничего необычного, предполагается устанавливать letodb в подразделениях, и делать выборки из БД подразделений

sashaBG: Select DVIG COPY TO ( n_Path + 'WORK' ) <<<<<<< где n_Path содержит "//127.0.0.1:2812/FIRMA/2010/01/" дает ошибку по типу данных файл WORK.dbf создается но структура разрушена !? letodb из CVS harbour из поставки MiniGUI 1.9 Раньше работало из с другими версиями Харбора

AlexMyr: Какие типы полей в базе? Клиентскую и серверную часть letodb пересобирали?

sashaBG: Все пересобирал , типы ( N15,3 C D )

Pasha: С xHarbour ошибки нет С Harbour сервер падает по непонятной причине на строке 5111 в letofunc.c: hb_xfree( pTransInfo->lpTransItems ); Что здесь неправильно - не пойму. Память выделялась - ее надо освободить. sashaBG, AlexMyr, напишите пожалуйста версию Harbour, с которой выполнялась сборка

AlexMyr: Только что собрал LetoDB /* $Id: Changelog,v 1.328 2010/11/15 18:15:03 ptsarenko Exp $ */ харбором Harbour 2.1.0beta2 (Rev. 15728) Copyright (c) 1999-2010, http://harbour-project.org/ Harbour Build Info --------------------------- Version: Harbour 2.1.0beta2 (Rev. 15728) Compiler: Borland C++ 5.5.1 (32-bit) Platform: Windows Vista 6.0.6002 Service Pack 2 PCode version: 0.3 ChangeLog last entry: 2010-11-02 18:42 UTC+0100 Viktor Szakats (harbour.01 syena r.hu) ChangeLog ID: ChangeLog 15728 2010-11-02 18:09:03Z vszakats Built on: Nov 2 2010 23:00:37 Build options: (Clipper 5.3b) (Clipper 5.x undoc) (UNICODE) запустил сервер, потом test_ta - все отработало нормально.

Pasha: У меня сервер падает на сборке Harbour * $Id: ChangeLog 15433 2010-09-04 10:30:41Z druzus $ Завтра пересоберу Harbour с SVN и протестирую.

sashaBG: test_tr собирается но дает ошибку данных на 32 строке и сервер падает

sashaBG: Попробовал и Harbour Rev.15832 Тоже самое , разница в том что когда сервер падает виндовс показывает сообшение "Abnormal programm termination"

AlexMyr: Тоже test_tr падает с ошибкой: Error LETO/1000 Data type error Called from LETO_DBCOPY(0) Called from MAIN(32) Error LETO/1000 Data type error Called from LETO_DBCOPY(0) Called from MAIN(32) Error LETO/1000 Data type error Error LETO/1000 Data type error

Pasha: Сегодня собрал letodb с SVN Harbour, и результат получился плачевный. manage еще соединяется с сервером, но при попытке работы с ним клиентских программ letodb сразу падает с gpf. Почему - еще не разбирался. Вчера у меня возникло предположение, что в Harbour некоторое время назад были какие-то уже устраненные баги, раз сервер падал на безобидном hb_xfree. Пока мне больше сказать нечего, времени копаться не было.

Pasha: Letodb под Harbour у меня заработал после вечерней пересборки. Правда, там чуть напортачили с литовской кодовой страницей. Оператор, из-за которого падает сервер, я пока закомментировал, так что copy to/sort on теперь работает. Но причина падения сервера так и осталась непонятной.

Петр: 2010-11-18 20:45 UTC+0200 Pavel Tsarenko (tpe2/at/mail.ru) * source/server/letofunc.c * memory leak for sort operation ! temporary hack for Harbour: gpf at hb_xfree( pTransInfo->lpTransItems ) in leto_Trans function Вот так работает hb_xfree( &pTransInfo->lpTransItems ); Добавлено: не все так просто Перекомпилировал Harbour c -DHB_FM_STATISTICS Получаем GPF letodb_crash.log [pre2]Breakdown at: 2010.11.18 23:48:59 Unrecoverable error 9010: ------------------------------------------------------------------------ User: 127.0.0.1 LEO-HOME test_tr.exe Command: trans;513;2;;F;1026;Code==2;;0;0;F;T;T;F;F;F;F;1;2;1,1;2,2; Table: \test.dbf[/pre2] hb_out.log [pre2]------------------------------------------------------------------------ Application Memory Allocation Report - E:\hb2-mingw\bin\test_tr.exe Terminated at: 2010.11.18 23:49:01 Total memory allocated: 60916 bytes (596 block(s)) Warning, memory allocated but not released: 86 bytes (6 block(s)) Block 1 00aaedf8 (size 4) DBCREATE(0), "00000200" Block 2 00aae570 (size 4) DBCREATE(0), "00000000" Block 3 00abc808 (size 23) DBCREATE(0), " 2Second )" Block 4 00abcd10 (size 4) LETO_DBCOPY(0), "00000200" Block 5 00abcd78 (size 4) LETO_DBCOPY(0), "00000000" Block 6 00abcde0 (size 23) LETO_DBCOPY(0), " ;" ------------------------------------------------------------------------ [/pre2]

Pasha: Но правильно ведь hb_xfree( pTransInfo->lpTransItems ); lpTransItems - это ссылка на массив DBTRANSITEM, для которого выделялась память, ее и надо передавать в hb_xfree, а не адресс ссылки. В прочих rdd Harbour так и делается Почему в letodb этот безобидный вызов сваливает сервер - пока не понятно. С DBTRANSINFO работа ведется вроде бы корректно, память не портится. pTransInfo->lpTransItems 2 раза не освобождается, больше никто hb_xfree вызвать не может. Я прямо перед вызовом hb_xfree ставил: leto_writelog(pTransInfo->lpTransItems, pTransInfo->uiItemCount * sizeof( DBTRANSITEM )); и в логе видел правильно заполненный массив DBTRANSITEM Пока какая-то мистика, которой не существует

sashaBG: Pasha А как себя ведет xHarbour , есть проблемы такого типа ?

Pasha: sashaBG пишет: Pasha А как себя ведет xHarbour , есть проблемы такого типа ? С xHarbour такой проблемы нет, освобождение памяти работает По поводу проблемы с Harbour: я попросил помощь клуба, т.е. написал в devlist. Но клуб молчит.

alx_on: Pasha пишет: hb_xfree( pTransInfo->lpTransItems ); Подобная проблема была и у меня. Все решилось совсем в другом месте (с другой переменной), неверно память до этого выделялась (т.е. писалась информация за пределами выделенного блока и, видимо, что то портилось в цепочках блоков-памяти) В моем случае это была дозапись признака конца строки ('\0') за конец выделенной памяти - иногда падало совсем в другом месте

Dimidrol: заранее извиняюсь за нубский вопрос. есть ли возможность не указывать host-адрес каждый раз при подключении таблиц бд? то есть не писать в команде USE или функции DBUSEAREA(...) имя или айпи сервера, а указать, например в leto.ini или еще каким другим способом.

Pasha: В команде USE / функции dbUseArea указывать параметры соединения обязательно, хотя бы затем, что программа (клиент) должна иметь возможность открывать файлы на нескольких серверах letodb Можете написать свою функцию, скажем leto_UseArea, которая добавляла бы к имени таблицы префикс - параметры соединения по умолчанию. Или сделайте свою команду USE вместо стандартной, в которой тоже поставлялись бы параметры соединения.

sashaBG: Letodb собран с xHarbour Compiler build 1.2.1 (SimpLex) (Rev. 6755) если в test_tr.prg заменить строку создания TEST.DBF на: dbCreate(cPath + 'test', {{'Code','N',2,0},{'Name','C',20,0},{'Name2','C',20,0},{'Name3','C',20,0},{'Name4','C',20,0},{'Name5','C',20,0}},, .T.) сервер падает не генерируя краш репорт это происходит после добавления {'Name5','C',20,0} с 5 пoлями работает .

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

sashaBG: Паша Вы сделали COMMIT , последнее что у меня есть: /* $Id: Changelog,v 1.330 2010/11/18 18:45:50 ptsarenko Exp $ */

Pasha: Да, сделал. Просто коммит видно не сразу, а сюда я написал буквально в ту же минуту

sashaBG: Сделал тест под Harbour (15953) и под xHarbour (6755) РАБОТАЕТ Спасибо Паша ! Кстати в letodbtray но для моего проекта е сделал исправление : потому что Letodb падает из за постоянного подключение и отключения я в цикле по таймеру сделал възов функцию IsAlive() вместо IsConnected(): FUNCTION IsAlive() Return leto_file( _Server+"USER.DBF" ) и таким образом серввер не падает. но для общего использования она не подойдет , нельзя ли сделать на C leto_islive() ? И еще интересное наблюдение : на серверах ( я пробую на windows Serwer 2008 ) скорость работы letodb заметно ниже чем на обычном XP процессор на сервере нагружается небольше 5% а под XP и Win7 доходит до 60% и больше , наверное ето потому что letodb не серверны процес.

Pasha: Вместо проверки существования файла лучше использовать вызов: lConnected := ! Empty(Leto_MgGetInfo())

PSP: Pasha пишет: коммит видно не сразу Паша, растолкуйте, плиз.

Pasha: PSP пишет: Pasha пишет: цитата: коммит видно не сразу Паша, растолкуйте, плиз. Имеется в виду коммит на CVS. Если делать чекаут от анонимуса, то последние коммиты видно не сразу, а через некоторое время, может даже через несколько часов. А чекаут от имени девелопера видит сразу все обновления других девелоперов.

PSP: Ясно. Просто у меня че-то данные не сразу становятся видны после транзакции. Пока не понял почему...

Pasha: PSP пишет: Просто у меня че-то данные не сразу становятся видны после транзакции. Пока не понял почему... Во время транзакции или после коммита ? Если во время транзакции, то мы с Александром эту тему уже обсуждали. Вкратце: до коммита транзакция хранится на клиенте, и, если при этом получать данные с сервера, то будут переданы еще не измененные данные.

PSP: Pasha пишет: до коммита транзакция хранится на клиенте Я так подозреваю, что commit внутри транзакции не решит вопрос? :)

AlexMyr: PSP пишет: Я так подозреваю, что commit внутри транзакции не решит вопрос? :) Вот кусок с test_ta leto_BeginTransaction() select NAKL2 for i := 1 to Len( aSumm ) append blank replace NORD with n_ord, DORD with d_ord, NPROD with i, SUMMA with aSumm sumAll += aSumm next select NAKL1 append blank replace NORD with n_ord, DORD with d_ord, SUMMA with sumAll leto_CommitTransaction() т.е. начало транзакции, что-то делаем с данными, конец транзакции. А Вы как работаете с транзакциями?

Pasha: LETO_COMMITTRANSACTION может только завершить транзакцию. После коммита все данные становятся видны, но транзакция завершилась, можно только начать новую. А dbCommit во время транзакции игнорируется.

PSP: AlexMyr пишет: А Вы как работаете с транзакциями? Также. Pasha пишет: LETO_COMMITTRANSACTION может только завершить транзакцию. После коммита все данные становятся видны, но транзакция завершилась, можно только начать новую. А dbCommit во время транзакции игнорируется. Дело в том, что пока не могу отловить глюк. Он то есть, то нет. Поэтому слегка невнятно выражаюсь. Ладно, пока оставим это. Выловлю (если), - сообщу.

PSP: Короче... Попробую сформулировать :) - dbf открывается при запуске проги и остается открытым до завершения; - используются транзакции; - одна из станций производит запись в dbf; - после завершения транзакции станция, производишая запись, видит изменения, а остальные - нет; - если другая станция тоже проведет транзакцию записи в этот dbf, она увидит и "свои" и "чужие" изменения; - изменения не видны также при просмотре файла вьювером; - если все станции прекращают работу, все изменения становятся видны. Использую: Harbour 2.0.0 LetoDB: Changelog,v 1.331 2010/12/15 18:15:14 ptsarenko (проверял еще на Changelog,v 1.322 2010/09/10 10:49:01 alkresin, то же самое) LetoDB запущен под Ubuntu 10.04 Станции - Windows XP SP3 Натолкните на мысль, пожалуйста... :)

Pasha: PSP пишет: - после завершения транзакции станция, производишая запись, видит изменения, а остальные - нет; Чтобы остальные станции увидели изменение, надо, чтобы они перечитали изменившиеся данные, т.е. сделали goto(recno()) или skip(0)

PSP: Pasha пишет: Чтобы остальные станции увидели изменение, надо, чтобы они перечитали изменившиеся данные, т.е. сделали goto(recno()) или skip(0) "Вот оно чё, Михалыч, вот оно чё..." :) Спасибо, Паш.

Pasha: PSP пишет: "Вот оно чё, Михалыч, вот оно чё..." :) Дык этот же момент надо учитывать и для файл-сервера, без leto Если одна станция сделала коммит, остальные его увидят, когда перечитают файл Тоже самое касается и sql. Это стандартый вопрос: почему после транзакции другие клиенты ее не видят. И на это есть стандартный ответ: представьте, что после каждой транзакции sql-сервер вдруг начнет плеваться данными на всех подключенных в этот момент клиентов... это же нехорошо ? Вот поэтому клиенты должны сами, того, как тот Магомед, идти к горе.

PSP: А как объяснить, что вьювер тоже не видит изменений?

Pasha: PSP пишет: А как объяснить, что вьювер тоже не видит изменений? То, что вьювер вообще получает доступ к таблице, открытой letodb, говорит нам, что letodb работает в режиме Share_Tables. Это неэффективный режим, в режиме монопольного доступа letodb работает лучше. А обьяснение простое. Сервер letodb - это тот же dbfcdx. А как известно, путь от простого dbCommit к физической записи данных на диск труден и долог. Сначала dbfcdx сбрасывает эти данные в буфер операционки. А уж когда она соизволит их записать на диск - можно только догадываться. И лишь после этого их сможет увидеть вьювер. Который, кстати, тоже может не сразу обновить данные, у него может свой буфер имеется.

PSP: Pasha пишет: letodb работает в режиме Share_Tables Нет. Я специально в ini-файле даже Share_Tables = 0 поставил. У меня тоже такая мысль была. По идее сервер не должен давать доступ.

PSP: Pasha пишет: Который, кстати, тоже может не сразу обновить данные, у него может свой буфер имеется Я его многократно открываю-закрываю. Результат одинаковый.

PSP: Сейчас попробовал в файл-серверном варианте с DBFCDX. Две станции пишут по-очереди в одно поле одной записи. При этом не используется ни DBCommit(), ни сдвиг указателя записи. Только Lock и UnLock. Причем, содержимое поля читается и перед записью, и после. Так вот, данные читаются всегда актуальные, на обеих станциях. Так, собственно, и Клиппер работает.

PSP: Pasha пишет: Тоже самое касается и sql. Это стандартый вопрос: почему после транзакции другие клиенты ее не видят. И на это есть стандартный ответ: представьте, что после каждой транзакции sql-сервер вдруг начнет плеваться данными на всех подключенных в этот момент клиентов... это же нехорошо ? Вот поэтому клиенты должны сами, того, как тот Магомед, идти к горе. Паша, извините за позднюю реакцию, диагональное чтение... На это могу сказать одно: если после завершения транзакции SQL-сервер не вернет клиенту актуальные данные, разве это нормально? У меня именно такая ситуация. Транзакция закончена, клиент запрашивает данные и получает... устаревшие. Разве клиент должен заботиться об актуальности данных на сервере?

Pasha: Нет конечно. После завершения транзакции все запрашиваемые данные должны быть актуальны. Разве в letodb не так ? Я говорил о том, что уже полученные клиентом данные могут быть неактуальны, и после транзакции с другого клиента надо повторить запрос

PSP: Pasha пишет: Разве в letodb не так ? У меня получается, что "не так". Даже после завершения транзакции одной станцией, другая получает устаревшие данные. Проверял на двух серверах: под Ubuntu и под XP. Причем файл-серверный вариант (см.выше) нормально работает.

Pasha: PSP пишет: У меня получается, что "не так". Тогда разбираемся более предметно. t1.prg: Field Code, Name Function main Local cPath := '//127.0.0.1:2812/', nKey := 0 REQUEST LETO RDDSETDEFAULT( "LETO" ) cls dbCreate(cPath + 'test', {{'Code','N',2,0},{'Name','C',20,0}}) use (cPath + 'test') shared new dbAppend() dbCommit() while nKey # 27 rlock() leto_BeginTransaction() Field->Code ++ dbCommit() leto_CommitTransaction() dbUnlock() ? 'Client 1', Recno(), Field->Code wait nKey := LastKey() enddo return nil t2.prg: Field Code, Name Function main Local cPath := '//127.0.0.1:2812/', nKey := 0 REQUEST LETO RDDSETDEFAULT( "LETO" ) cls use (cPath + 'test') shared new while nKey # 27 goto 1 ? 'Client 2', Recno(), Field->Code wait nKey := LastKey() enddo return nil Запускам t1, выполняем первую транзакцию, выводим значение поля после транзакции Запускаем t2 - видим то же значение Переключаемся на t1, выполняем следующую транзакцию, переключаемся на t2 - видим то же самое значение. И так далее Получается что "так" Где собака порылась ?

PSP: С "goto 1" все "так". А без него "нет так". А теперь тот же пример, но без Leto, через DBFCDX. Исключаем "goto 1" - все работает "так". Даже без dbCommit(). В чем прикол? Почему драйвер DBFCDX позволят другой станции без сдвига указателя прочитать актуальные данные, а выполнение leto_CommitTransaction() не позволяет? Извините за нудность, просто налетел на эту фичу на рабочей базе. Кстати, в версиях Leto начала 2010 года (точно не скажу, не сохранилось), все работало "так" и без "goto". :)

Pasha: PSP пишет: С "goto 1" все "так". А без него "нет так". Без goto данные на 2-м клиенте не обновляются. Первый раз клиент 2 выдал запрос серверу на 1-ю запись и получил ее. Затем в цикле он, не запрашивая обновленные данные, выводит то значение, которое он получил первый раз, то есть необновленное. Как вы себе представляете, клиентская программа должна сама по себе без пинка запрашивать обновленные данные с сервера ? Чтобы обновить запись, надо либо сместить указатель текущей записи и вернуться на нужную, либо выдать dbgoto(recno()) или dbskip(0). Правда, в лето есть еще механизм кеширования skip, но здесь он не работает, не будем усложнять.

Pasha: Вот пример без лето и без goto t1.prg Field Code, Name Function main Local cPath := '', nKey := 0 cls dbCreate(cPath + 'test', {{'Code','N',2,0},{'Name','C',20,0}}) use (cPath + 'test') shared new dbAppend() dbCommit() while nKey # 27 rlock() Field->Code ++ dbCommit() dbUnlock() ? 'Client 1', Recno(), Field->Code wait nKey := LastKey() enddo return nil t2.prg Field Code, Name Function main Local cPath := '', nKey := 0 cls use (cPath + 'test') shared new while nKey # 27 // goto 1 ? 'Client 2', Recno(), Field->Code wait nKey := LastKey() enddo return nil И что мы видим: да никакой мистики с фантастикой, 2-й клиент видит необновленные данные. Все работает, как и должно работать

PSP: Pasha пишет: Как вы себе представляете, клиентская программа должна сама по себе без пинка запрашивать обновленные данные с сервера ? Чтобы обновить запись, надо либо сместить указатель текущей записи и вернуться на нужную, либо выдать dbgoto(recno()) или dbskip(0). Я всегда думал, что выдача актуальных данных - забота сервера. Клиент вправе считать полученные данные актуальными в любой момент времени и не знает, когда ему нужно сдвинуть указатель, а когда не нужно. Тем более, если указатель уже находится на нужной записи. Ладно, вопрос можно считать закрытым. Паше спасибо за терпение. :)

Pasha: PSP пишет: Я всегда думал, что выдача актуальных данных - забота сервера. Единственная забота сервера - обслужить клиента, т.е обработать его запрос. Сервер сам по себе клиенту ничего не посылает. Если бы это было так, то это был бы не клиент-сервер, а сервер-сервер. На стороне клиента пришлось бы делать какой-то диспетчер запросов, принимать команды с сервера...

PSP: Да уж... Развил я тут тему... :) Паша, еще раз спасибо за терпение.

Dimka: как letodb сейчас работает на многоядерных системах?

Pasha: Dimka пишет: как letodb сейчас работает на многоядерных системах? В letodb используется 2 потока. Значит, будет работать как обычное многопоточное приложение. Я специально не исследовал этот вопрос, но думается, что каждое ядро будет выполнять отдельный поток

Pasha: Добавил новую функцию: Leto_Commit() Она заменяет вызовы: dbCommit() dbUnlock() Обычно клиент посылает серверу 3 пакета : для обновления записи, для commit и для unlock Новая функция посылает только один пакет для всех этих операций. Таким образом, при обновлении данных количество пакетов можно уменьшить втрое

Andrey: Pasha пишет: Таким образом, при обновлении данных количество пакетов можно уменьшить втрое Классное решение ! Спасибо за рацпредложение и исполнение его !

Dimka: пытаюсь начать пользоваться letodb. на одном большом рассчете программка начинает течь и занимает 1гб оперативы и более. успокойте меня, скажите что это изза того, что используются индексы NTX. и команда USE делает последний из перечисленных индексов активным.

Pasha: Dimka пишет: успокойте меня, скажите что это изза того, что используются индексы NTX. и команда USE делает последний из перечисленных индексов активным. Фантазировать мы не будем. Лучше попробуйте выяснить, какое действие является причиной протечки. Очень уж воды много выливается. У меня вот приличная по размеру программа занимает всего 12М, а тут целый гектар, впечатляет.

AlexMyr: Dimka пишет: пытаюсь начать пользоваться letodb. на одном большом рассчете программка начинает течь и занимает 1гб оперативы Попробуйте сделать маленький самодостаточный пример и на нем потестировать, и если будут проблемы, тогда пример в студию.

Dimka: Использование letodb нарушило логику программы и она входила в бесконечный цикл. SET EXACT OFF не включало мягкий поиск как раньше и DBSEEK возвращал False. Вызов DBSEEK со вторым параметром решил проблему. Еще, повторю, после использования команды USE с открытием нескольких индексов активный индекс по умолчанию - последний, вместо первого. UPD. SET EXACT OFF включает мягкий поиск, но он то ли слетает, то ли неправильно работает. dbseek выдает False там где должен выдавать True.

Pasha: Dimka пишет: SET EXACT OFF не включало мягкий поиск как раньше и DBSEEK возвращал False. Вообще-то set exact предназначен для другого - для сравнения строк, и не имеет отношения ни к letodb, ни к подсистеме rdd вообще Может быть, имеется в виду set softseek ? Так он обрабатывается еще на уровне функции dbSeek, и letodb получает уже готовый параметр, и сам не должен учитывать эту настройку

Dimka: Ыыыыы...точняк! Я еще поэкспериментирую, но факт остается фактом. Один и тот же код при DBFNTX и LETO(NTX) выдает разные результаты. В программе черт ногу сломит, поэтому примера пока нет. [pre2]* DBFNTX ... sost->(dbseek(a1)) // .T. sost->(dbseek(a2)) // .T. sost->(dbseek(a3)) // .T. [/pre2] [pre2]* LETO ... sost->(dbseek(a1)) // .T. sost->(dbseek(a2)) // .T. sost->(dbseek(a3)) // .F. !!!!!!!!!! [/pre2] В моем случаем вызов sost->(dbseek(a3), .T.) помогло.

Pasha: Dimka пишет: Еще, повторю, после использования команды USE с открытием нескольких индексов активный индекс по умолчанию - последний, вместо первого. Да, несовместимость с dbfntx имеет место быть однако. После dbSetIndex aka OrdListFocus в dbfntx фокус не меняется, а leto/ntx - меняется. Надо поправить

Pasha: Сравнение производительности rddnet и letodb Такой простенький тест. Если в cdxnetap.prg заменить функцию AppendSomeRecords [pre]STATIC FUNCTION AppendSomeRecords( nRecords ) LOCAL i LOCAL cPeerName := CdxNetGetClientIP( s_nConxn ) LOCAL nSec := Seconds() FOR i := 1 TO nRecords DbAppend() REPLACE abc->name WITH cPeerName REPLACE abc->dob WITH date() REPLACE abc->time WITH time() REPLACE abc->salary WITH 10000 + i NEXT DbCommit() ? 'Append ' + Str(Seconds() - nSec) nSec := Seconds() go top while ! eof() skip enddo ? 'Skip ' + Str(Seconds() - nSec) nSec := Seconds() for i := 1 to nRecords goto int(i/256) + 256 - (i%256) next ? 'Random ' + Str(Seconds() - nSec) wait RETURN NIL[/pre] И вызвать ее с параметром 20000, То rddnet даст результат: Append 103.81 Skip 7.80 Random 6.91 Результат letodb: Append 8.72 Skip 0.64 Random 3.95 Вывод: по операциям, которые оптимизируются в letodb: добавление, последовательная выборка, производительность letodb превышает производительность rddnet более чем на порядок (в 12 раз). По неоптимизированым операциям (грубо) в 2 раза. Причина этого очевидна. rddnet базируется на основе usrrdd и реазизован в медленном prg - коде. Это позиционируется как его преимущество и "правильный" подход. Естественно, что letodb со своей "неправильной" архитектурой сильно выигрывает в производительности. В rddnet сделать такую оптимизацию, как в letodb, будет затруднительно. Априори letodb находится в выигрышном положении. Удивляет другое. И letodb, и rddnet не вызвал почему-то особого интереса среди основной массы разработчиков Харбора. Если будет доведен rddnet, в котором будет реализована базовая функциональность dbfcdx, и у него будет более-менее приемлемая производительность, это будет хорошо для сообщества. Возможность выбора из 2-х продуктов - это польза для обеих. Но и с rddnet кроме Притпала Беди никто не возится

AlexMyr: Pasha пишет: Удивляет другое. И letodb, и rddnet не вызвал почему-то особого интереса среди основной массы разработчиков Харбора. Может пока заняты? Еще надо посмотреть что выдаст Przemek, тоже обещал, но вроде коммерческое. А он наверное сделает.

Pasha: Захотелось оптимизировать работу с memo В letofunc.c в ф-ии leto_rec после case HB_FT_MEMO: case HB_FT_BLOB: case HB_FT_PICTURE: case HB_FT_OLE: вместо выборки значения поля, при котором значение читается из dbt/fpt SELF_GETVALUE( (AREAP)pArea, ui+1, pItem ); проверять на непустое значение номера блока в самом файле dbf При этом снизится загрузка сервера. В связи с этим у меня вопрос: кроме размерности для memo 10 и 4 байта есть ли еще какие-нибудь форматы ?

AlexMyr: Pasha пишет: В связи с этим у меня вопрос: кроме размерности для memo 10 и 4 байта есть ли еще какие-нибудь форматы ? В harbour как я понимаю поддержка только этих HB_FT_MEMO: HB_FT_IMAGE: HB_FT_BLOB: HB_FT_OLE: или Вы про другое?

Pasha: Да, именно про это Я сделал вычисление размера мемо вместо чтения самого мемо-поля из дбт/фпт файла. Мемо-поля теперь считываются только по запросу с клиента

Pasha: Надо делать в LetoDB обработку запросов в нескольких потоках. В связи с этим в letofunc.c надо избавиться от некоторых static-переменных вроде pBufCrypt, bHrbError и некоторых других, чтобы разные потоки их совместно не использовали. Отсюда вопрос: куда лучше их затолкать: в USERSTRU, или сделать отдельную структуру LETOTHREAD, специально для этих целей ?

Pasha: По поводу обработки запросов на сервере в нескольких потоках. Наколько я понимаю, реализовать это на основе letocore.c не получится по причине того, что при обработке запросов потоком будет установлено окружение харбора: текущая р/о, кодовая страница, set-установки, которое разное для разных запросов, и потоки будет мешать друг другу. Надо делать это на основе leto_2.c Какие при этом могут быть ньюансы ?

alx_on: Pasha Примерно, полгода назад я пытался заинтересовать Кресина и остальных в этом форуме вопросом о разделении по потокам Но никто не откликнулся. Тогда я для себя все это дописал. Но т.к. никому было не интересно - сделал только под себя и свои нужды: например, совершенно не дорабатывал и не проверял транзакции и leto_Sum (leto_udf - точно не будет работать) Установка в качестве службы под WIN Есть дополнительные оптимизации по минимизации запросов к серверу (во завернул!) Например: 1. DBOI_ISDESC 2. DBOI_CUSTOM 3. DBOI_UNIQUE 4. SCOPE Исправление ошибок: 1. выделение памяти 2. GOTOP SKIP -1 GOTO( RECNO() ) - не сбрасывал флаги (типа BOF(), EOF() и т.д.) 3. Клиент неверно проверял признак блокировки в команде UN_LOCK( номер запись ) если номер записи не совпадал с текущей 4. Исправление ошибки с добавлением записи в заблокированную таблицу 5. Что то еще (не помню) Режим отладки (в INI "debug = 10") Настройка кол-ва таблиц (в INI "tables_max = 10000") Настройка кол-ва соединений (в INI "users_max = 1500") Файлы отладки (letodb*.log) создаются в папке с исполняемым файлом (Из INI выкинут параметр "LOG") При запуске в лог пишется основная информация о настройках Возможность запуска letodb (собранной как служба) в режиме командной строки (параметр "test") Ограничения: 1. Серверная часть писалась ТОЛЬКО под Harbour (из SVN, за декабрь 2010) 2. Проверялась только под mingw (win) и gcc (linux,mac) Известные глюки: 1. Редко - клиент отваливается, но сервер не сбрасывает соединение (dbf остаются открытыми) Бывает при обрыве связи (чаще), засыпании компа Сильно не мешает, но неакуратно (если требуется доступ к dbf, например, для удаления - не даст без перезапуска leto) Все это работает в боевом режиме в 3 местах (по 50-70 клиентов, каждый клиент открывает около 10 соединений, примерно 60 файлов в каждом соединении) Старая версия в такой ситуации стабильно падала раз в день Если интересно могу выложить

Pasha: Конечно выкладывайте. Но, поскольку многие собирают letodb и с xHarbour, могут возникнуть проблемы при сборке. Может пришлете мне сначала, я проверю сборку под xHb (с letocore.c), и, если все ОК, тогда сбросите на CVS Мой адрес tpe2 (at) mail . ru

Pasha: К слову. У меня letodb не падал ни разу, работает месяцами. Правда, он собран с xHarbour и крутится под win

alx_on: Pasha пишет: Конечно выкладывайте. Но, поскольку многие собирают letodb и с xHarbour Клиентская часть собираться должна и с xHarbour Для серверной части скачать и скомпилять Harbour не большая проблема

alx_on: http://zalil.ru/30561093

Pasha: Собрал letodb-mt под bcc55-harbour, а также клиентскую библиотеку под xHarbour Для сборки под bcc пришлось учесть различия в диалектах bcc и mingw Для сборки под xHarbour в common/common_c.c закомментировал //#include "hbthread.h" она вроде там не нужна, и в client/letomgmn.c я добавил #ifdef __XHARBOUR__ #define hb_snprintf snprintf #endif Сервис успешно запустился, клиентская программа с letodb работает. При вызове leto_MemoRead возникает gpf, с причиной пока не разбирался. Остальное вроде работает Результат правки сырцов отправил Вам по почте, на адрес, указанный в Changelog. По поводу дальнейшего развития letodb. Думаю, надо оставить вариант для сервера и без сервиса, для возможности работы под win98 По поводу поддержки сервера letodb без mt для xHarbour и старой версии Harbour - думаю, что последнее слово должно быть за Кресиным. Он ведь еще использует старую версию Hb А то, что вариант с mt надо включать в CVS - однозначно надо ! Отличная работа

Wolfv: Доброе время суток. Где то я наверное торможу, подскажите пожалуйста где ошибка? Есть клиентское приложение в котором присутствует следующий код: ... REQUEST LETO RDDSETDEFAULT( "LETO" ) Set EXCLUSIVE OFF use ( BaseDir + 'messtag.dbf' ) Alias mt new via "LETO" Set index TO ( BaseDir + "messtag_id.cdx" ), ( BaseDir + "messtag_tag.cdx" ), ( BaseDir + "messtag_val.cdx" ) .... Фрагмент процедуры поиска : ... Select mt Set order TO 3 Set filter TO MT->TAG = nTg DBSeek( PadR( AllTrim( Form_1.TxBox1.value ), FIELDSIZE( FieldPos( "VALUE" ) ) )) ... Если запущено одно клиентское приложение все работает нормально. При запуске второго клиента при попытке поиска (на втором клиенте ) вылетает ошибка LETO/1201 - Файл не проиндексирован. Сервер запущен с параметром Share_Tables = 1

Pasha: А зачем Вы создаете 3 индексных файла ? Можно ведь обойтись одним с тремя тэгами Конечно, я в таком режиме не проверял совместимость

Wolfv: Спасибо попробую переписать. Когда писал изначально было под DBFNTX, ну а когда перешел на LETO поленился изменять индексирование. Ну и база наполняется (и индексы строятся) другим приложением которое стоит на сервере и работает на прямую.

Pasha: Так letodb можно использовать и с dbfntx. тогда и менять ничего не прийдется

Wolfv: Переписал создание индексов через tag все заработало нормально. Спасибо!

Andrey: Pasha пишет: А зачем Вы создаете 3 индексных файла ? Можно ведь обойтись одним с тремя тэгами А я тоже использую отдельные индексные файлы... У меня их много. Неужели придется переписывать ВСЕ это ???

Pasha: Andrey пишет: А я тоже использую отдельные индексные файлы... Это что, для cdx, что ли ? Повторю, для cdx мне и в голову не приходило проверить leto в таком режиме. cdx - это compound indexes. Какой смысл использовать cdx, если по прежнему механически создавать отдельный файл для каждого индекса ? Это просто непонимание инструмента, который используешь

SergejKis: Всем привет. Столкнулся с пробемой LetoDb: на localhost работает отлично. В локалке или интернет соединении клиент валится (сервер ломается с crash... файлом или без): Error LETO/1000 Data type error LETO_COMMITTRANSACTION(0) ... TestCdxToLeto.prg .... cRdd := "LETO" ...... dbUseArea( lNew, cRdd, cFile, cAls, .F. ) // Exclusive .... lDel := (inp)->( Deleted() ) FOR i := 1 TO k; aVal := (inp)->( FieldGet(aPos) ) NEXT leto_BeginTransaction() dbAppend() FOR i := 1 TO k; FieldPut(aPou, aVal) NEXT IF lDel; dbDelete() ENDIF leto_CommitTransaction() (inp)->( dbSkip(1) ) .... LetoDb rev.1.337 от 2011-02-23 18:00 Сборка клиента и сервера на Харбор 2.1.0rc1 для BCC 5.5.1 (от gfilatov2002 )http://minigui.mylivepage.ru/file/?fileid=8540. В выходной файл может быть записано от 0 до 1000 записей и валится ... Пробовал Харбор 2.1.0Rc2для BCC 5.5.1 (от gfilatov2002) ... то же самое. Подскажите в какую сторону смотреть ...

Pasha: Так падает сервер, а на клиенте возникает из-за этого ошибка, насколько я понял ? Покажите, что в letodb_crash.log

SergejKis: letodb_crash.log: ------------------- Breakdown at: 2011.04.08 10:04:36 Unrecoverable error 6005: Exception error: %s Exception Code:C0000005 Exception Address:00431CFF EAX:00000000 EBX:78000000 ECX:00000018 EDX:001EDC10 ESI:0000000E EDI:001EDD68 EBP:0012FB0C CS:EIP:001B:00431CFF SS:ESP:0023:0012FAA8 DS:0023 ES:0023 FS:003B GS:0000 Flags:00010206 CS:EIP: 8B 48 04 83 E1 F8 3B 4D FC 74 3A 8B CB C1 E9 1F SS:ESP: 0012FB68 001EDC1C 00608BD4 00000002 004C0ED8 00000950 00000000 0000000E 00000001 004C0ED0 001EDC10 004C0ED0 0043156F 00000120 00000158 0012FB68 C stack: EIP: EBP: Frame: OldEBP, RetAddr, Params... 00431CFF 0012FB0C 0012FB18 00432107 001EDC18 00432107 0012FB18 0012FB2C 00498107 001EDC1C 001EDC1C 00608BD4 00498107 0012FB2C 0012FB40 00498056 00608BD4 001E47A4 0012FB94 00498056 0012FB40 0012FB5C 00440FF0 0012FB94 00000000 001E47A4 001E582C 00000000 00440FF0 0012FB5C 0012FB74 0040D330 0012FB94 00000018 00000000 40E1B680 0040D330 0012FB74 6F74004C 20424420 76726553 76207265 392E302E 3B4E3B35 00000000 0000000D 555C3A43 54454843 Modules: 0x00400000 0x000D1000 C:\UCHET\LETO\01\leto2011.exe 0x77680000 0x0013D000 C:\Windows\SYSTEM32\ntdll.dll 0x76050000 0x000D4000 C:\Windows\system32\kernel32.dll 0x75850000 0x0004A000 C:\Windows\system32\KERNELBASE.dll 0x723E0000 0x00007000 C:\Windows\system32\WSOCK32.DLL 0x75D30000 0x00035000 C:\Windows\system32\WS2_32.dll 0x764D0000 0x000AC000 C:\Windows\system32\msvcrt.dll 0x761C0000 0x000A1000 C:\Windows\system32\RPCRT4.dll 0x777E0000 0x00006000 C:\Windows\system32\NSI.dll 0x75AF0000 0x000C9000 C:\Windows\system32\USER32.DLL 0x77860000 0x0004E000 C:\Windows\system32\GDI32.dll 0x77850000 0x0000A000 C:\Windows\system32\LPK.dll 0x76620000 0x0009D000 C:\Windows\system32\USP10.dll 0x75AD0000 0x0001F000 C:\Windows\system32\IMM32.DLL 0x76750000 0x000CC000 C:\Windows\system32\MSCTF.dll 0x75210000 0x0003C000 C:\Windows\system32\mswsock.dll 0x74D60000 0x00005000 C:\Windows\System32\wshtcpip.dll ------------------------------------------------------------------------ User: 212.93.100.167 T43 tst_leto.exe Command: ta; Table: \test\u08.dbf PC двухядерный с Win 7 32 Professional. У меня был пример netio с hb 2.0.0 он отработал четко

SergejKis: Ещё проблема. Крах сервера вызывает обращение к отсутсвующим переменным сервера (что не должно было бы происходить). Пример: test_var.prg после connect вызов: lRes := leto_varDel( "main","var_int" ) ? "var_int =" ,leto_varGet( "main","var_int" ) letodb_crash.log: Breakdown at: 2011.04.09 07:50:17 Unrecoverable error 6005: Exception error: %s Exception Code:C0000005 Exception Address:0040C26E EAX:00000000 EBX:003F5B34 ECX:FFFFFFFF EDX:003F9391 ESI:00000000 EDI:00000000 EBP:0012FB78 CS:EIP:001B:0040C26E SS:ESP:0023:0012FB34 DS:0023 ES:0023 FS:003B GS:0000 Flags:00010246 CS:EIP: F6 47 09 02 74 39 F6 47 09 08 74 33 8B 45 08 2B SS:ESP: 00000015 003F9380 003F5B34 00000076 00496863 003F5B34 00000076 0049687F 00000000 00000032 00000011 00000003 000007DB 003F9391 003F9389 003F9384 C stack: EIP: EBP: Frame: OldEBP, RetAddr, Params... Modules: 0x00400000 0x000D1000 C:\BK8\HBLETO\LETO2011\SRV\server.exe 0x7C900000 0x000B0000 C:\WINDOWS\system32\ntdll.dll 0x7C800000 0x000F4000 C:\WINDOWS\system32\kernel32.dll 0x64D00000 0x00031000 C:\Program Files\Alwil Software\Avast5\snxhk.dll 0x71AD0000 0x00009000 C:\WINDOWS\system32\WSOCK32.DLL 0x71AB0000 0x00017000 C:\WINDOWS\system32\WS2_32.dll 0x77C10000 0x00058000 C:\WINDOWS\system32\msvcrt.dll 0x71AA0000 0x00008000 C:\WINDOWS\system32\WS2HELP.dll 0x77DD0000 0x0009B000 C:\WINDOWS\system32\ADVAPI32.dll 0x77E70000 0x00091000 C:\WINDOWS\system32\RPCRT4.dll 0x77D40000 0x00090000 C:\WINDOWS\system32\USER32.DLL 0x77F10000 0x00046000 C:\WINDOWS\system32\GDI32.dll 0x76390000 0x0001D000 C:\WINDOWS\system32\IMM32.DLL 0x71A50000 0x0003F000 C:\WINDOWS\system32\mswsock.dll 0x662B0000 0x00058000 C:\WINDOWS\system32\hnetcfg.dll 0x71A90000 0x00008000 C:\WINDOWS\System32\wshtcpip.dll ------------------------------------------------------------------------ На мой взгляд, не хватает: 1. функции типа leto_CreateBase("//127.0.0.1:2812/MyBase/2011/") - создание катлога базы для таблиц 2. функций доступа и установки значения к переменным сервера на стороне сервера для работы с тригерами (HB_FUNC).

Pasha: leto_varGet пофиксил Против функции создания папки и функций для доступа к переменным на сервере возоржений нет, могу их сделать С транзакциями пока непонятно. Локальный и удаленный сервер работает совершенно одинаково, и если валится второй, то должен падать и первый. Надо разбираться. Может выложите файлик, на котором сервер спотыкается ?

SergejKis: В zip положил и ac.log с клиента. click here Я сам удивился, что сервер стал валится. в задачу уже встроил, отладил на localhost, поставил на сервер, начал первоначальную загрузку базы делать и .... облом. Из файлов проходит только один, в котором 28 записей и 30 полей. С функциями, если сделаете БОЛЬШОЕ спасибо, но как к этому отнесется А.Кресин ... смотрел ранние посты и там по созданию каталога шли горячие возражения.

SergejKis: Попобовал такой пример: TestCdxToLeto.prg .... cRdd := "LETO" dbCreate( cFile, aCrt, cRdd ) .... UseArea( .T., cRdd, cFile, , .F. ) // Open Exclusive ... lDel := (a)->( Deleted() ) FOR i := 1 TO k; aVal := (a)->( FieldGet(aPos) ) NEXT dbAppend() IF ! NetErr() FOR i := 1 TO k; FieldPut(aPou, aVal) NEXT IF lDel; dbDelete() ENDIF dbCommit() ENDIF ... Сервер ломается причем без letodb_crash.log с MsgStop("Abnormal ... canceled ....") в разных местах: 1. запуск первый. на клиенте error : ---------- 09.04.2011 18:54:57 Harbour 2.1.0rc1 (Rev. 16300) ------------ Program : C:\BK8\LETO\KLIENT\INF\tst_leto.exe 09.04.2011 18:47:32, 1140.224Kb Memory : 0Kb (Win32) CPU - x86, Windows XP 5.1.2600 Service Pack 2 DiskSpace: 23924Mb Error LETO/1000 Data type error = DBCREATE(0) ... 2. запуск второй. на клиенте error : ---------- 09.04.2011 19:00:43 Harbour 2.1.0rc1 (Rev. 16300) ------------ Program : C:\BK8\LETO\KLIENT\INF\tst_leto.exe 09.04.2011 18:47:32, 1140.224Kb Memory : 0Kb (Win32) CPU - x86, Windows XP 5.1.2600 Service Pack 2 DiskSpace: 23923Mb Error LETO/1000 Data type error = DBCOMMIT(0) .... в выходном файле на сервере (u08.dbf) 243 записи. В localhost все работает ok! Есть у меня файл на 100000 записей, он тоже ok!.

Pasha: Насколько я понял, речь идет о двух разных ошибках. 1. Ошибка dbCreate На массив со структурой грешить нечего, так что речь идет о строке-имени файла с параметрами коннекта. Покажите, как Вы создаете файл, то есть первый параметр dbCreate. Эта ошибка клиента, или на ней падает сервер ? Если ошибка клиента, тогда должна быть запись в letodb.log на сервере. Там что-то есть ? Если падает сервер, то этого просто не может быть. Ошибка возникает всегда, или эпизодически ? 2. Как видно, это простое копирование одного файла во второй в цикле по всем записям. Так ошибка возникает и с использованием транзакций, и без транзакций, и простым dbCommit() ? Причем падает именно сервер ? У меня такие операции работают на сотнях тысячах - миллионах записей, dbCommit, без транзакций. Причем исключительно в локалке. Правда, сервер собран под xHarbour. Со сборкой сервера в zip-архиве я смогу проверить только на следующей неделе, дома у меня локалки нет. По поводу файловых операций. Leto_file и еще пару функций - переименование и удаление таблиц - сделал я, 3 года назад. Причем сделал неправильно: надо было делать их тогда средствами rdd: letoDrop, letoExists, letoRename. Но тогда эти операции rdd я не знал (не попалась на глаза эта специфика харбора), и у меня сработал клипперовский стереотип, я сделал их по аналогии с известными функциями. Что сделано - то сделано, и большой крамолы в этом нет. Тогда у нас было обсуждение, как при этом обеспечить безопасность сервера. Сошлись на флаге EnableFileFunc, который на сервере устанавливает админ, и на работе файловых функций только в папке, где находится БД. В свете этого я не вижу никаких возражений против создания каталога, если у пользователя есть соответствующие права. Если можно создать таблицу БД, то почему нельзя создать каталог ? Поскольку в rdd нет операции создания каталога, то надо ее делать отдельной функцией

Pasha: Добавил функции LETO_VARSET( nUserStru, cGroupName, cVarName, xValue[, nFlags ) --> lSuccess LETO_VARGET( nUserStru, cGroupName, cVarName ) --> xValue LETO_VARINCR( nUserStru, cGroupName, cVarName ) --> nValue LETO_VARDECR( nUserStru, cGroupName, cVarName ) --> nValue LETO_VARDEL( nUserStru, cGroupName, cVarName ) на сервере

SergejKis: 1.Первый параметр dbCreate://80.232.248.196:2120/test/u08 но дело где то не в этом, то что я описал про запуски это действительно было два запуска в такой последовательности, т.е. ошибка плавает, раньше у меня было и на dbUseArea(0) (log file на сохранил). Сейчас запускал - переписалось 281 запись в файл на сервере и снятие опять на dbCommit(0). letodb.log имеет вид: .... 04/07/11 21:17:20: Leto DB Server has been started. 07.04.11 21:22:49: Abnormal canceled ... leto2011.exe 04/07/11 21:22:50: Leto DB Server has been started. 04/07/11 21:25:13: Server has been closed. 04/07/11 21:25:14: Leto DB Server has been started. 04/07/11 21:25:14: Server has been closed. 04/07/11 21:25:19: Leto DB Server has been started. 07.04.11 21:28:59: Abnormal canceled ... leto2011.exe 04/07/11 21:29:00: Leto DB Server has been started. 08.04.11 10:04:40: Abnormal canceled ... leto2011.exe 04/08/11 10:04:41: Leto DB Server has been started. 09.04.11 18:52:10: Abnormal canceled ... leto2011.exe 04/09/11 18:52:11: Leto DB Server has been started. 04/09/11 18:53:57: Server has been closed. 04/09/11 18:54:00: Leto DB Server has been started. 09.04.11 18:57:56: Abnormal canceled ... leto2011.exe 04/09/11 18:57:56: Leto DB Server has been started. 10.04.11 11:14:27: Abnormal canceled ... leto2011.exe 04/10/11 11:14:28: Leto DB Server has been started. Сообщение: Abnormal canceled ... - это сообщение аналога letotray на AutuIt3 (ловит появление окна с сообщением, убирает его и перезапускает server letodb) Локалки и у меня дома нет вся работа через мобильный интернет 3G (сейчас я на даче). 2.Спасибо БОЛЬШОЕ за функции и обьяснения по истории файловых операций в letodb. 3. Кто вперед падает сервер или клиент - наверно клиент, не получив или получив от сервера что-то с ошибкой и не повторив получение или передачу ..., но точно сказать не могу не знаю. Подскажите что попробовать, попробую. Зашлите со своего клиента по указанному адресу файл (желательно имя файла другое для отличия),

Pasha: Запустил тест на копирование полмиллиона записей, пока скопировалась 1000 записей, процесс идет, посмотрим, дойдет ли до конца Кстати, Вы можете запустить свой тест на моем сервере, adsl Укртелеком Сейчас строка коннекта: //95.135.104.42:2812/test LetoDb запущен Я могу попробовать у себя и 3g-соединение, но это не сегодня. Возможно, проблема в нестабильности 3g-соединения, но это пока только предположение

Pasha: Обрыв на 2119 записей. Падал ли сервер ? Я вижу, что коннект с ним сейчас есть, но может быть его поднял letotray ? Сейчас коннект с сервером есть, но таблицу я открыть не могу

Pasha: Вроде бы Ваш сервер не падал, в параметрах соединения - запущен 1 час с минутами назад. Но сейчас с ним коннекта уже нет

SergejKis: Сервер упал, причем завис с ~ 25% занятости процессора и занятым testU08.dbf, снял процесс и перезапустился сервер. letodb.log: 04/10/11 11:14:28: Leto DB Server has been started. 10.04.11 14:23:50: Abnormal canceled ... leto2011.exe 10.04.11 14:23:55: Abnormal canceled ... leto2011.exe 04/10/11 14:23:55: Leto DB Server has been started. 10.04.11 15:00:12: Process close ... leto2011.exe 04/10/11 15:00:12: Leto DB Server has been started. letodb_crash.log: Breakdown at: 2011.04.10 14:23:47 Unrecoverable error 6005: Exception error: %s Exception Code:C0000005 Exception Address:004309A4 EAX:001EAC30 EBX:004C0CA8 ECX:1EAC2F00 EDX:001EAC30 ESI:004C0D40 EDI:00000000 EBP:0012FAD4 CS:EIP:001B:004309A4 SS:ESP:0023:0012FA68 DS:0023 ES:0023 FS:003B GS:0000 Flags:00010206 CS:EIP: 89 41 0C 8B 55 D0 8B 4D B4 89 4A 08 8B 45 D0 89 SS:ESP: 0012FB68 004C0CA8 00000158 776DB6FC 70827440 00000B84 212CBAD4 57638709 1EAC2F00 00000007 EBDAA0BF 0012F9D8 004C0ED4 0012FB1C 004C0ED4 001EAC30 C stack: EIP: EBP: Frame: OldEBP, RetAddr, Params... 004309A4 0012FAD4 0012FB1C 0043156F 004C0CA8 00000158 0012FB68 001E45EC 00000150 000000FF 0012FB0C 0012FB08 0043156F 0012FB1C 0012FB2C 0043204B 00000150 001EC7DC 0043204B 0012FB2C 0012FB40 0049800C 0000014C 001E45EC 0012FB94 0049800C 0012FB40 0012FB5C 00440FF0 0012FB94 00000000 001E45EC 001E582C 00000000 00440FF0 0012FB5C 0012FB74 0040D330 0012FB94 00000018 00000000 40E94E60 0040D330 0012FB74 3831004C 30303632 76720031 76207265 392E302E 3B4E3B35 00000000 0000000D 555C3A43 54454843 Modules: 0x00400000 0x000D1000 C:\UCHET\LETO\01\leto2011.exe 0x77680000 0x0013D000 C:\Windows\SYSTEM32\ntdll.dll 0x76050000 0x000D4000 C:\Windows\system32\kernel32.dll 0x75850000 0x0004A000 C:\Windows\system32\KERNELBASE.dll 0x723E0000 0x00007000 C:\Windows\system32\WSOCK32.DLL 0x75D30000 0x00035000 C:\Windows\system32\WS2_32.dll 0x764D0000 0x000AC000 C:\Windows\system32\msvcrt.dll 0x761C0000 0x000A1000 C:\Windows\system32\RPCRT4.dll 0x777E0000 0x00006000 C:\Windows\system32\NSI.dll 0x75AF0000 0x000C9000 C:\Windows\system32\USER32.DLL 0x77860000 0x0004E000 C:\Windows\system32\GDI32.dll 0x77850000 0x0000A000 C:\Windows\system32\LPK.dll 0x76620000 0x0009D000 C:\Windows\system32\USP10.dll 0x75AD0000 0x0001F000 C:\Windows\system32\IMM32.DLL 0x76750000 0x000CC000 C:\Windows\system32\MSCTF.dll 0x75210000 0x0003C000 C:\Windows\system32\mswsock.dll 0x74D60000 0x00005000 C:\Windows\System32\wshtcpip.dll ------------------------------------------------------------------------ User: 95.135.104.42 NEPTUN t6.exe Command: add;514;1;0;0; Table: \test\test08.dbf Unrecoverable error 6005: Exception error: %s Exception Code:C0000005 Exception Address:00431374 EAX:004C0D40 EBX:001EAC2F ECX:1EAC2F00 EDX:1EAC2F00 ESI:004C0CA8 EDI:00000007 EBP:01B5FD0C CS:EIP:001B:00431374 SS:ESP:0023:01B5FCD4 DS:0023 ES:0023 FS:003B GS:0000 Flags:00010206 CS:EIP: 89 42 0C EB 05 E8 7E 4B 07 00 8B C7 C1 E0 03 8B SS:ESP: 00000000 00000000 0000002C 01B5FCF8 758585F4 EA75F08F 00000064 00000000 00000000 75214798 00000060 0000006C 1EAC2F00 00080066 01B5FD1C 0043204B C stack: EIP: EBP: Frame: OldEBP, RetAddr, Params... 00431374 01B5FD0C 01B5FD1C 0043204B 0000002C 00000000 0043204B 01B5FD1C 01B5FD30 0042E9FB 00000028 00000000 00000000 0042E9FB 01B5FD30 01B5FD3C 0041ADB8 00000000 0041ADB8 01B5FD3C 01B5FD50 0041B9B3 00000000 0039000C 001EA844 0041B9B3 01B5FD50 01B5FDF4 00405D26 00000000 00000000 00000004 001E582C 00000001 01B5FD94 776DB6FC 70827440 00405D26 01B5FDF4 01B5FE3C 004064BB 001E582C 003AAE8A 00000001 01B5FE38 00000000 00000000 0000000E 003AAE8A 004064BB 01B5FE3C 01B5FE60 0040A737 001E582C 003AAE8A 00000001 00000000 004C08B4 00000000 001E582C 0040A737 01B5FE60 01B5FEA8 0040CDDF 001E582C 004A73D4 01A60000 013921A0 00000000 01B5FF54 004A73D4 01A60000 0040CDDF 01B5FEA8 01B5FF78 004A71D0 00000000 00000000 00000000 013921A0 00000094 00000006 00000001 00001DB0 004A71D0 01B5FF78 01B5FF88 004A7203 013921A0 004A73D4 004A7203 01B5FF88 01B5FF94 760A1194 013921A0 760A1194 01B5FF94 01B5FFD4 776DB429 013921A0 D08821D8 00000000 00000000 013921A0 00000000 00000000 00000000 776DB429 01B5FFD4 01B5FFEC 776DB3FC 004A71EC 013921A0 00000000 00000000 Modules: 0x00400000 0x000D1000 C:\UCHET\LETO\01\leto2011.exe 0x77680000 0x0013D000 C:\Windows\SYSTEM32\ntdll.dll 0x76050000 0x000D4000 C:\Windows\system32\kernel32.dll 0x75850000 0x0004A000 C:\Windows\system32\KERNELBASE.dll 0x723E0000 0x00007000 C:\Windows\system32\WSOCK32.DLL 0x75D30000 0x00035000 C:\Windows\system32\WS2_32.dll 0x764D0000 0x000AC000 C:\Windows\system32\msvcrt.dll 0x761C0000 0x000A1000 C:\Windows\system32\RPCRT4.dll 0x777E0000 0x00006000 C:\Windows\system32\NSI.dll 0x75AF0000 0x000C9000 C:\Windows\system32\USER32.DLL 0x77860000 0x0004E000 C:\Windows\system32\GDI32.dll 0x77850000 0x0000A000 C:\Windows\system32\LPK.dll 0x76620000 0x0009D000 C:\Windows\system32\USP10.dll 0x75AD0000 0x0001F000 C:\Windows\system32\IMM32.DLL 0x76750000 0x000CC000 C:\Windows\system32\MSCTF.dll 0x75210000 0x0003C000 C:\Windows\system32\mswsock.dll 0x74D60000 0x00005000 C:\Windows\System32\wshtcpip.dll Unrecoverable error 6005: Exception error: %s Exception Code:C0000005 Exception Address:004309A4 EAX:001EAC30 EBX:004C0CA8 ECX:1EAC2F00 EDX:001EAC30 ESI:004C0D40 EDI:00000000 EBP:0012FAD4 CS:EIP:001B:004309A4 SS:ESP:0023:0012FA68 DS:0023 ES:0023 FS:003B GS:0000 Flags:00010206 CS:EIP: 89 41 0C 8B 55 D0 8B 4D B4 89 4A 08 8B 45 D0 89 SS:ESP: 0012FB68 004C0CA8 00000158 776DB6FC 70827440 00000B84 212CBAD4 57638709 1EAC2F00 00000007 EBDAA0BF 0012F9D8 004C0ED4 0012FB1C 004C0ED4 001EAC30 C stack: EIP: EBP: Frame: OldEBP, RetAddr, Params... 004309A4 0012FAD4 0012FB1C 0043156F 004C0CA8 00000158 0012FB68 001E45EC 00000150 000000FF 0012FB0C 0012FB08 0043156F 0012FB1C 0012FB2C 0043204B 00000150 001EC7DC 0043204B 0012FB2C 0012FB40 0049800C 0000014C 001E45EC 0012FB94 0049800C 0012FB40 0012FB5C 00440FF0 0012FB94 00000000 001E45EC 001E582C 00000000 00440FF0 0012FB5C 0012FB74 0040D330 0012FB94 00000018 00000000 40E94E60 0040D330 0012FB74 3831004C 30303632 76720031 76207265 392E302E 3B4E3B35 00000000 0000000D 555C3A43 54454843 Modules: 0x00400000 0x000D1000 C:\UCHET\LETO\01\leto2011.exe 0x77680000 0x0013D000 C:\Windows\SYSTEM32\ntdll.dll 0x76050000 0x000D4000 C:\Windows\system32\kernel32.dll 0x75850000 0x0004A000 C:\Windows\system32\KERNELBASE.dll 0x723E0000 0x00007000 C:\Windows\system32\WSOCK32.DLL 0x75D30000 0x00035000 C:\Windows\system32\WS2_32.dll 0x764D0000 0x000AC000 C:\Windows\system32\msvcrt.dll 0x761C0000 0x000A1000 C:\Windows\system32\RPCRT4.dll 0x777E0000 0x00006000 C:\Windows\system32\NSI.dll 0x75AF0000 0x000C9000 C:\Windows\system32\USER32.DLL 0x77860000 0x0004E000 C:\Windows\system32\GDI32.dll 0x77850000 0x0000A000 C:\Windows\system32\LPK.dll 0x76620000 0x0009D000 C:\Windows\system32\USP10.dll 0x75AD0000 0x0001F000 C:\Windows\system32\IMM32.DLL 0x76750000 0x000CC000 C:\Windows\system32\MSCTF.dll 0x75210000 0x0003C000 C:\Windows\system32\mswsock.dll 0x74D60000 0x00005000 C:\Windows\System32\wshtcpip.dll Unrecoverable error 6005: Exception error: %s Exception Code:C0000005 Exception Address:00431374 EAX:004C0D40 EBX:001EAC2F ECX:1EAC2F00 EDX:1EAC2F00 ESI:004C0CA8 EDI:00000007 EBP:01B5FD0C CS:EIP:001B:00431374 SS:ESP:0023:01B5FCD4 DS:0023 ES:0023 FS:003B GS:0000 Flags:00010206 CS:EIP: 89 42 0C EB 05 E8 7E 4B 07 00 8B C7 C1 E0 03 8B SS:ESP: 00000000 00000000 0000002C 01B5FCF8 758585F4 EA75F08F 00000064 00000000 00000000 75214798 00000060 0000006C 1EAC2F00 00080066 01B5FD1C 0043204B C stack: EIP: EBP: Frame: OldEBP, RetAddr, Params... 00431374 01B5FD0C 01B5FD1C 0043204B 0000002C 00000000 0043204B 01B5FD1C 01B5FD30 0042E9FB 00000028 00000000 00000000 0042E9FB 01B5FD30 01B5FD3C 0041ADB8 00000000 0041ADB8 01B5FD3C 01B5FD50 0041B9B3 00000000 0039000C 001EA844 0041B9B3 01B5FD50 01B5FDF4 00405D26 00000000 00000000 00000004 001E582C 00000001 01B5FD94 776DB6FC 70827440 00405D26 01B5FDF4 01B5FE3C 004064BB 001E582C 003AAE8A 00000001 01B5FE38 00000000 00000000 0000000E 003AAE8A 004064BB 01B5FE3C 01B5FE60 0040A737 001E582C 003AAE8A 00000001 00000000 004C08B4 00000000 001E582C 0040A737 01B5FE60 01B5FEA8 0040CDDF 001E582C 004A73D4 01A60000 013921A0 00000000 01B5FF54 004A73D4 01A60000 0040CDDF 01B5FEA8 01B5FF78 004A71D0 00000000 00000000 00000000 013921A0 00000094 00000006 00000001 00001DB0 004A71D0 01B5FF78 01B5FF88 004A7203 013921A0 004A73D4 004A7203 01B5FF88 01B5FF94 760A1194 013921A0 760A1194 01B5FF94 01B5FFD4 776DB429 013921A0 D08821D8 00000000 00000000 013921A0 00000000 00000000 00000000 776DB429 01B5FFD4 01B5FFEC 776DB3FC 004A71EC 013921A0 00000000 00000000 Modules: 0x00400000 0x000D1000 C:\UCHET\LETO\01\leto2011.exe 0x77680000 0x0013D000 C:\Windows\SYSTEM32\ntdll.dll 0x76050000 0x000D4000 C:\Windows\system32\kernel32.dll 0x75850000 0x0004A000 C:\Windows\system32\KERNELBASE.dll 0x723E0000 0x00007000 C:\Windows\system32\WSOCK32.DLL 0x75D30000 0x00035000 C:\Windows\system32\WS2_32.dll 0x764D0000 0x000AC000 C:\Windows\system32\msvcrt.dll 0x761C0000 0x000A1000 C:\Windows\system32\RPCRT4.dll 0x777E0000 0x00006000 C:\Windows\system32\NSI.dll 0x75AF0000 0x000C9000 C:\Windows\system32\USER32.DLL 0x77860000 0x0004E000 C:\Windows\system32\GDI32.dll 0x77850000 0x0000A000 C:\Windows\system32\LPK.dll 0x76620000 0x0009D000 C:\Windows\system32\USP10.dll 0x75AD0000 0x0001F000 C:\Windows\system32\IMM32.DLL 0x76750000 0x000CC000 C:\Windows\system32\MSCTF.dll 0x75210000 0x0003C000 C:\Windows\system32\mswsock.dll 0x74D60000 0x00005000 C:\Windows\System32\wshtcpip.dll Unrecoverable error 6005: Exception error: %s Exception Code:C0000005 Exception Address:00431374 EAX:004C0D40 EBX:001EAC2F ECX:1EAC2F00 EDX:1EAC2F00 ESI:004C0CA8 EDI:00000007 EBP:01B5FD0C CS:EIP:001B:00431374 SS:ESP:0023:01B5FCD4 DS:0023 ES:0023 FS:003B GS:0000 Flags:00010206 CS:EIP: 89 42 0C EB 05 E8 7E 4B 07 00 8B C7 C1 E0 03 8B SS:ESP: 00000000 00000000 0000002C 01B5FCF8 758585F4 EA75F08F 00000064 00000000 00000000 75214798 00000060 0000006C 1EAC2F00 00080066 01B5FD1C 0043204B C stack: EIP: EBP: Frame: OldEBP, RetAddr, Params... 00431374 01B5FD0C 01B5FD1C 0043204B 0000002C 00000000 0043204B 01B5FD1C 01B5FD30 0042E9FB 00000028 00000000 00000000 0042E9FB 01B5FD30 01B5FD3C 0041ADB8 00000000 0041ADB8 01B5FD3C 01B5FD50 0041B9B3 00000000 0039000C 001EA844 0041B9B3 01B5FD50 01B5FDF4 00405D26 00000000 00000000 00000004 001E582C 00000001 01B5FD94 776DB6FC 70827440 00405D26 01B5FDF4 01B5FE3C 004064BB 001E582C 003AAE8A 00000001 01B5FE38 00000000 00000000 0000000E 003AAE8A 004064BB 01B5FE3C 01B5FE60 0040A737 001E582C 003AAE8A 00000001 00000000 004C08B4 00000000 001E582C 0040A737 01B5FE60 01B5FEA8 0040CDDF 001E582C 004A73D4 01A60000 013921A0 00000000 01B5FF54 004A73D4 01A60000 0040CDDF 01B5FEA8 01B5FF78 004A71D0 00000000 00000000 00000000 013921A0 00000094 00000006 00000001 00001DB0 004A71D0 01B5FF78 01B5FF88 004A7203 013921A0 004A73D4 004A7203 01B5FF88 01B5FF94 760A1194 013921A0 760A1194 01B5FF94 01B5FFD4 776DB429 013921A0 D08821D8 00000000 00000000 013921A0 00000000 00000000 00000000 776DB429 01B5FFD4 01B5FFEC 776DB3FC 004A71EC 013921A0 00000000 00000000 Modules: 0x00400000 0x000D1000 C:\UCHET\LETO\01\leto2011.exe 0x77680000 0x0013D000 C:\Windows\SYSTEM32\ntdll.dll 0x76050000 0x000D4000 C:\Windows\system32\kernel32.dll 0x75850000 0x0004A000 C:\Windows\system32\KERNELBASE.dll 0x723E0000 0x00007000 C:\Windows\system32\WSOCK32.DLL 0x75D30000 0x00035000 C:\Windows\system32\WS2_32.dll 0x764D0000 0x000AC000 C:\Windows\system32\msvcrt.dll 0x761C0000 0x000A1000 C:\Windows\system32\RPCRT4.dll 0x777E0000 0x00006000 C:\Windows\system32\NSI.dll 0x75AF0000 0x000C9000 C:\Windows\system32\USER32.DLL 0x77860000 0x0004E000 C:\Windows\system32\GDI32.dll 0x77850000 0x0000A000 C:\Windows\system32\LPK.dll 0x76620000 0x0009D000 C:\Windows\system32\USP10.dll 0x75AD0000 0x0001F000 C:\Windows\system32\IMM32.DLL 0x76750000 0x000CC000 C:\Windows\system32\MSCTF.dll 0x75210000 0x0003C000 C:\Windows\system32\mswsock.dll 0x74D60000 0x00005000 C:\Windows\System32\wshtcpip.dll

Pasha: Ясно, что ничего не ясно. Что такое ошибка 6005 - такого кода в харборе нет. Пока подозрения или на особенности сборки с текущей версией харбора, или неправильной обработки ошибок в сети в letodb Я поиграюсь у себя с удаленным соединением. но это будет на неделе Ну а мой сервер видно ? manage.exe с ним коннектится ? Можете запустить свой тест ?

SergejKis: Дело не в 3G, мой товарищ по работе из дома получает тоже самое, в четверг в офисе в лосалке тоже. NETIO с 3G, из дома и в локалке копировал файлы нормально. Ваш testu08.dbf содержит 2118 записей. К Вам на сервер мой файл ушел отлично.

Pasha: Да, я вижу, пришло 1801 записей А теперь я запустил leto2011.exe, Вашу сборку Запустите еще свой тест, прийдет ли файл Хотя я уже увидел, что у меня клиент сразу падает на gpf при попытке коннекта с leto2011.exe, и сервер тоже падает, причем это локальный коннект Значит, какая-то проблема со сборкой Я соберу с текущим харбором letodb, и посмотрю, что получится. Хотя и раньше собирал многократно..

SergejKis: У меня локальный коннект на этой сборке не падал никогда (кроме реальных моих ошибок), вот letodb от 20.05.2010 падал от засыпания/просыпания компа и так ... от работы ..., но по постам я понял, что много было исправлено. Но к сожалению другой сборки letodb у меня нет и я взял текущую вместе с hb. В реальной работе сейчас hb 2.0. К Вам на сервер мой файл повторно ушел ok!.

SergejKis: Паша, для функций доступа на стороне сервера в тригерах nUserStru вроде как не нужен (мы имеем реальную область) или я не в курсе ? Пример: FUNCTION hs_opentable( nUserStru, cCommand ) BEGIN SEQUENCE leto_SetUserEnv( nUserStru ) *** Sx_SetTrigger( TRIGGER_PENDING, "hs_letoTrigger" ) *** dbUseArea( .F. , iif( nDriver == 1,"DBFNTX",Nil ), ; cFileName, cRealAlias, ; ( lShareTables .AND. lShared ), ; ( lShareTables .AND. lReadOnly ), ; Iif( !Empty(cdp ),cdp,Nil ) ) RECOVER USING oError lres := .F. END SEQUENCE ... FUNCTION hs_letoTrigger( nEvent, nArea, nPos, xTrigVal ) LOCAL n Sx_SetTrigger( TRIGGER_DISABLE, ProcName() ) DO CASE CASE nEvent == EVENT_UPDATE // 3 IF ( n := (nArea)->( FieldPos("DATEUPDATE") ) ) > 0; (nArea)->( FieldPut(n, hb_TtoS(hb_DateTime())) ) ENDIF CASE nEvent == EVENT_APPEND // 4 ... CASE nEvent == EVENT_DELETE // 5 ... CASE nEvent == EVENT_RECALL // 6 ... ENDCASE Sx_SetTrigger( TRIGGER_ENABLE, ProcName()) RETURN .T.

Pasha: nUserStru необходим при создании переменной. Я его добавил во все функции для того, чтобы соблюдать единые правила для всех серверных функций

SergejKis: Совершенно с этим согласен ! Надо, чтобы функция обрабатывала nUserStru := NIL Еще вопрос: LETO_VARGETLIST( nUserStru, [cGroupName] ) возвращает массив только имен переменных? Если это так, то хотелось бы иметь LETO_VARGETLIST( nUserStru, [cGroupName][,lValueGet := .F.] ) - имена и значения (снимок)

Pasha: nUserStru обязателен для создания переменных. Это связано с правами на доступ к ним. Но в конце концов, каждое действие на сервере выполняется по запросу пользователя, так что он всегда определен. В том числе его надо передавать и триггеру. А сами триггеры лучше конечно устанавливать отдельным запросом с клиента. По поводу LETO_VARGETLIST: возвращать в этом случае двумерный массив ? И тогда надо сделать для клиентского вызова этой функции аналогичное поведение Только прийдется проверять права на доступ к переменным.

Pasha: По поводу падения сервера. Прогнать тест у меня сейчас совершенно нет времени Но у меня же leto2011 не упал. Может быть, что-то блокирует firewall ? Или попробуйте работать с другим портом, хотя бы стандартным 2812.

SergejKis: Говоря о LETO_VARGETLIST я имел ввиду клиента, т.к. ценность в одном обращении к серверу (чтобы не сильно ломать, то что есть можно возвращать строкой: VAR_1=N101 первый байт тип). По поводу прав доступа к переменным ... мы же их только читаем, поэтому использование этого режима на совести разработчика. Полностью согласен с тем, что Вы написали, но ... Триггеры с клиента ... это большой вопрос - надо ли переносить алгоритмы расчетов на сторону сервера ? Харбур, на мой взгляд, это толстый клиент и все расчеты только на нем. Но если такой инструмент (триггеров) будет ... кому-то он пригодится. Говоря о nUserStru := NIL, я имел ввиду только сторону сервера - получить/установить переменную по группе без учета nUserStru, а создавать переменные только с клиента. Если обработка nUserStru := NIL трудозатратна - вопрос однозначно снимается. Еще о переменных, какая MAX длина имени переменной.

SergejKis: Firewall, Norton antivirus, leto2011.exe, порты - все прописано и разрешено. NETIO сервер собраный по поведению аналогично letodb на hb 2.0 на тот же порт (другой не можем у провайдера Lattelecom платный сеанс связи и не факт что откроют то о чем просишь), полученный exe переименован в leto2011.exe - передачу файлов на сервер отрабатывает, но об этом я уже писал ... Вопрос такой, теущая сборка letodb на 2.0 пойдет ? Если нет, то где взять стабильную сборку ?

Pasha: Прогнал leto2011.exe в своей локалке. Копирует хоть несколько тысяч, хоть сотни тысяч записей Покажите, что у Вас letodb.ini Попробуйте прогнать у себя letodb, собранный под xHarbour: http://files.mail.ru/4P6Q5N

SergejKis: letodb.ini [MAIN] ; Port = 2812 Port = 2120 DataPath = . EnableFileFunc = 1 Пропустил оба теста с транзакцией и без на u08.dbf все прошло отлично, причем где то в два раза быстрее счетчик индикатор колбасит. Запустил u08.dbf на 15000 записей - надо ждать ... Все в 3G, но по поведению клиента чувствую, что будет все ok!

Pasha: Кстати, letodb поддерживает команду COPY TO / функцию __dbCopy То есть, подобную операцию лучше предоставить выполнять серверу

SergejKis: Все 15000 переписались отлично. Клиент собран на 2.1.0rc1 для BCC 5.5.1 (от gfilatov2002 ).

SergejKis: Я попробовал, когда она появилась, но получил DosError 53 разбираться нет времени, а в задачу встроен такой алгоритм загрузки данных на сервер.

SergejKis: Собрал сервер и клиента на hb 2.0.0. Ситуация, по сравнению с hb 2.1.0rc1, улучшилась, то только для теста без транзакций. С танзакцией файл u08.dbf (1801 rec) ни разу не переписался на сервер. Без транзакций через раз пересылался.

AlexMyr: Паша, только что попробовал собрать последний letodb и получил Harbour 2.1.0rc2 (Rev. 16566) Compiler: Borland C++ 5.5.1 (32-bit) Platform: Windows XP 5.1.2600 Service Pack 3 Error E2451 source\server\letovars.c 833: Undefined symbol 'HB_ITEM' in function HB_FUN_LETO_VARGETLIST Error E2379 source\server\letovars.c 833: Statement missing ; in function HB_FUN_LETO_VARGETLIST Error E2140 source\server\letovars.c 834: Declaration is not allowed here in function HB_FUN_LETO_VARGETLIST Error E2451 source\server\letovars.c 837: Undefined symbol 'Temp' in function HB_FUN_LETO_VARGETLIST Хотел в maillist но получилось к Вам, тут продублирую.

Pasha: Хмм, xHb собрал даже без варнингов Вечером если успею, поправлю (к нам тут Барселона приезжает)

AlexMyr: Pasha пишет: (к нам тут Барселона приезжает) Удачи

Pasha: Поправил, хоть мне и не совсем ясно, с каких это пор в Harbour использование HB_ITEM стало нелегитимым PHB_ITEM (ссылка на HB_ITEM) ведь можно, а определены они в одном hbapi.h Заодно добавил проверку прав доступа. Для этого и нужен nUserStru. Но если для переменной флаг LETO_VOWN не установлен, то права не проверяются, и соответственно nUserStru можно опустить

AlexMyr: Все собралось нормально, спасибо. Собрал manage и вот что получилось (поле номера порта)

Pasha: Что-то изменилось в hwgui Какой hwgui используется при сборке ?

AlexMyr: hwgui * $Id: Changelog 1623 2011-04-02 07:34:40Z druzus $

SergejKis: Продолжу тему, чего еще не хватает в letodb, на мой взгляд (после опыта перевода одной задачи с sql): 1.Если рассматривать cGroupName, как таблицы в памяти, то требуется еще наличие функции на клиенте (возможно и на сервере) LETO_VARGETGROUP() --> aList Функция на клиенте LETO_VARGETLIST( [cGroupName [, nMaxLen]] ), наверно, тоже должна иметь вид: LETO_VARGETLIST( [cGroupName [, nMaxLen][, lValue]] ). 2.Оператора INSERTUPDATE. В рамках существующей транзакции это могло бы выглядеть так: leto_BeginTransaction() sele AAA dbAppend() Replace ... sele BBB leto_Insert(cKeyValueSeek1) Replace .... sele CCC leto_Insert(cKeyValueSeek2) Replace .... leto_CommitTransaction() т.е. leto_Insert(...) должна в буфер транзакции записать инструкцию на выполнение типа: IF dbSeek(...) DoRlock(...) ELSE dbAppend() ENDIF По хорошему, ключ поиска, можно было бы не задавать (IndexKey(0) серверу и так известен), но это не принципиально ... Так как транзакции на сервере выполняются последовательно (если я правильно понимаю), то проблем с конфликтом dbRLock() не должно быть. 3.Функции leto_LockTable({cT1, cT2, ...}[, nCountTimeout]) и leto_UnLockTable([{cT1, cT2, ...}]), выполняющиеся сервером. nCountTimeout - кол-во циклов ожидания как в DoRLock( n ) Возможно я много хочу ..., но я совершенно отвык писать с использованием dbRLock(), dbUnLock() и считайте что я стал фанатом транзакций.

Pasha: SergejKis пишет: 1.Если рассматривать cGroupName, как таблицы в памяти, то требуется еще наличие функции на клиенте (возможно и на сервере) LETO_VARGETGROUP() --> aList Функция на клиенте LETO_VARGETLIST( [cGroupName [, nMaxLen]] ), наверно, тоже должна иметь вид: LETO_VARGETLIST( [cGroupName [, nMaxLen][, lValue]] ). LETO_VARGETLIST так и работает. Если название группы опущено, то возвращается список групп. Если задано - список переменных этой группы. По поводу таблиц в памяти. Харбор поддерживает нативные таблицы в памяти - см. contrib/hbmemio. Тогда уж лучше поднять их поддержку в letodb, чтобы не использовать суррогатное решение с переменными памяти.

AlexMyr: По поводу хотелок, хотелось бы вести лог подключений к серверу, можно опционально через letodb.ini log_connect = 0, типа: login ip (name) date time logout ip (name) date time ... Вот

SergejKis: Это МЕЧТА !!! Но действительность заставляет крутится. Я же с sql на letodb ... LETO_VARGETLIST() действительно возвращает список групп, я же проверял - это меня занесло ... А что по поводу на клиенте LETO_VARGETLIST( [cGroupName [, nMaxLen][, lValue]] ) - возвращать на группу (как на сервере) массив переменных со значениями при lValue = .T. ?

SergejKis: По поводу, суррогатного решения с переменными памяти, попробую обяснить. В sql были триггера, которые вели общую таблицу со списком прикладных таблиц и значением TimeStamp модификации, т.е. любое изменение в прикладной таблице вызывало изменение TimeStamp в общей таблице. Клиент сначала делает запрос к общей таблице и получает список изменившихся таблиц и только потом приступает к запросам на изменения из нужных таблиц. Так как алгоритм клиента задачи (при переходе к letodb, т.е. sql клиент остался и может работать) не меняется, то использование переменных letodb для этих целей, я так думаю, не есть криминал. Так же как в sql переменные (таблицы) можно сгруппировать по задачам и общие. Вот как-то так ...

Pasha: Добавил функцию LETO_MAKEDIR Что касается поддержки hb_memio, то сделать это достаточно просто. Надо при создании/открытии таблиц/индексов проверять имя на mem: и в случае успеха не приклеивать к нему префикс cDataPath. Ну и собирать сервер letodb с библиотекой hbmemio Может быть, сделать отдельный флаг при сборке

Pasha: По поводу времени модификации, жаль, что заголовок dbf содержит только дату создания. Иначе можно было бы обойтись запросом dbInfo( DBI_LASTUPDATE )

Pasha: SergejKis пишет: А что по поводу на клиенте LETO_VARGETLIST( [cGroupName [, nMaxLen][, lValue]] ) - возвращать на группу (как на сервере) массив переменных со значениями при lValue = .T. ? Так эта функция изначально так и работает, если задать параметр nMaxLen: LETO_VARGETLIST( cGroupName , 100 ) вернет двумерный массив со значениями переменных. А nMaxLen Александр наверное ввел, чтобы ограничить обьем передаваемых данных.

SergejKis: Паша, большое спасибо за разъяснения - не понял правильно идею второго параметра в leto_VarGetList, а потому и не попробовал. С dbInfo( DBI_LASTUPDATE ) - это очень давно жаль ... А почему бы в letodb не сделать механизм как в MySql, первое поле типа TimeStamp заполнять временем модификации при всех операциях с записью таблицы. Понимая, что такое поле уже может быть использовано в dbf (у пользователей letodb), предлагаю добавить свое имя поля, что-то вроде __LETO_UPD типа C/T. Также можно добавить поле __LETO_ID и после dbAppend() заполнять RecNo(). Т.е. если в структуре такие поля есть их заполнять. Включать такой режим через letodb.ini. hbmemio хотел заняться после перевода задач на letodb (уж очень достало администрирование на чужих PC с чужими администраторами). Но пока со сборкой своего сервера заклинило ... . Похоже на пару-тройку недель с letodb придется все отложить - возникла срочная работа - а жаль ... Паша, я правильно понял, это Max длина имени переменной (letovars.c): #define VARS_ALLOC 10 Если да, то по нынешним временам маловато будет ?!

Pasha: SergejKis пишет: Паша, я правильно понял, это Max длина имени переменной (letovars.c): #define VARS_ALLOC 10 Если да, то по нынешним временам маловато будет ?! VARS_ALLOC предназначен для выделения памяти в группе под LETO_VAR - память выделяется не под одну переменную, а сразу под 10, для оптимизации выделения. Это вообще не ограничение. А nMaxLen задает ограничение для длины строки с именами и значениями переменных группы, которую сервер вернет клиенту. Я б такой, чтобы это ограничение убрать вообще.

SergejKis: Паша, большое спасибо за разъяснения. Хотел еще спросить (посмотрел, что есть по Rdd и не увидел или не нашел похожих функций) есть ли механизм работы с буфером записи в HB ? В VO есть на уровне Rdd: VoDbRecordGet() и VoDbRecordPut(cBuff) читает и пишет всю запись, включая признак удаления. Скорость, при применении, сумасшедшая.

Pasha: В харборе таких функций нет, да и в них нет необходимости. Просто работа с записью изначально так и сделана: Запись считывается при позиционировании на нее в буфер, чтение поля - это просто выборка из буфера, запись поля - это запись в буфер А сам буфер сбрасывается в файл по dbCommit или другим операциям. Оптимизировать можно что-то неоптимальное, а здесь и так все оптимально. Я что-то сомневаюсь, что в VO по-другому. Разве что обращение к полям сделано неоптимально, но этот вряд ли. Ведь VO делался на основе клиппера. А написать такие функции я могу что называется "с колес", прямо сейчас: #include "hbapi.h" #include "hbapirdd.h" HB_FUNC( DBRECORDGET ) { AREAP pArea = ( AREAP ) hb_rddGetCurrentWorkAreaPointer(); USHORT uiRecLen; PHB_ITEM pItem = hb_itemPutNI( pItem, 0 ); char *pRec; if( pArea && (SELF_INFO( pArea, DBI_GETRECSIZE, pItem ) == SUCCESS) && ( SELF_GETREC( pArea, &pRec ) == SUCCESS ) ) { hb_retclen( pRec, hb_itemGetNI(pItem) ); } hb_itemRelease( pItem ); } HB_FUNC( DBRECORDPUT ) { AREAP pArea = ( AREAP ) hb_rddGetCurrentWorkAreaPointer(); PHB_ITEM pItem = hb_itemPutNI( pItem, 0 ); if( pArea && ISCHAR(1) && (SELF_INFO( pArea, DBI_GETRECSIZE, pItem ) == SUCCESS) && hb_parclen(1) >= hb_itemGetNI(pItem) ) { SELF_PUTREC( pArea, hb_parc(1) ); } hb_itemRelease( pItem ); } Извини, не проверял (с) к/ф Брат Но я сомневаюсь, что скорость при их использовании существенно увеличится. Оптимизируется только преобразование части строки в ITEM, а это некритичная операция

Pasha: Я наверное добавлю в letodb установку серверных триггеров с клиента, т.е. поддержку dbInfo( DBI_TRIGGER, <cProcName> )

leo: Заканчиваю переводить первое приложение на Letodb. Большое спасибо Паше за то, что прояснил многие вещи. Два вопроса к тем, кто уже давно работает с Letodb. 1) Не получилось показать процесс индексации файлов так как это было раньше. У кого-то это получается? Если да подскажите как вы это сделали. 2) Кто-то реализовал работу с семафорами в Letodb И если да нельзя ли поделиться результатами работы. Очень не хочется быть в очередной раз изобретателем велосипеда.

Pasha: leo пишет: 1) Не получилось показать процесс индексации файлов так как это было раньше. У кого-то это получается? Если да подскажите как вы это сделали. Сейчас это невозможно. Индексация происходит так: клиент посылает запрос серверу на создание индекса, и ждет ответа. Как только индекс создан, приходит ответ. Опции EVAL, EVERY в команде INDEX не поддерживаются. Чтобы это сделать, необходимо, чтобы сервер в процессе индексации посылал клиенту каждые EVERY записей сообщение, и (наверное) ждал от клиента квитанции о его получении. На мой взгляд, это излишне. Я не говорю, что это невозможно, и не буду возражать, если кто-то это сделает, но сам делать не буду.

SergejKis: leo пишет: 2) Кто-то реализовал работу с семафорами в Letodb И если да нельзя ли поделиться результатами работы. Очень не хочется быть в очередной раз изобретателем велосипеда. От семафоров сам очень давно отказаля, а для реализации в letodb используйте механизмы работы с переменными leto_var.... По поводу индексации (это мое мнение), если длительная (по времени) делайте в фоне, захватывая таблицу(ы) Exclusive. Для коротких, если очень надо, используйте функции hb_idleadd(...), hb_idledel(...). Подробнее в примерах каталога test.

SergejKis: Паша пишет: Я наверное добавлю в letodb установку серверных триггеров с клиента, т.е. поддержку dbInfo( DBI_TRIGGER, <cProcName> ) Это здорово и очень важно и нужно !!! Но ... Что делать, если на одну таблицу разные кленты будут делать: dbInfo( DBI_TRIGGER, "ProcName_1" ) dbInfo( DBI_TRIGGER, "ProcName_2" ) ... Ведь триггер (мое мнение) это свойство таблицы, не зависящее от клиента. Если бы, в letodb был файл описания таблицы (как sixnsx), то можно было бы в нем: [MAIN] Driver = CDX Trigger = MyTable1 ... [FIELDS] ; структура ... [INDEX] ; индексы/тэги ... А так, наверное, надо устанавливать первый и отшивать остальные по ошибке, возлагая все на разработчика

SergejKis: Паша пишет: А написать такие функции я могу что называется "с колес", прямо сейчас: Паша это ОЧЕНЬ оперативно ! Как будет время, надо даже ради интереса попробовать.

Pasha: С триггерами сделал так: Если в letodb.ini указать опцию Trigger = <cFuncName> или PendingTrigger = <cFuncName> и соответствующую функцию включить в letoudf.hrb, то это будет как раз глобальный триггер letodb Также можно использовать установку триггера для рабочей области с клиента: dbInfo(DBI_TRIGGER, <cFuncName>) cFuncName также должна существовать на сервере. При этом надо иметь в виду, что такой локальный триггер будет вызываться и для операций с р/о, вызываемых с других клиентов. Можно также временно отключать триггер вызовом с клиента: dbInfo(DBI_TRIGGER, .f.) и включать его: dbInfo(DBI_TRIGGER, .t.) Функцию-триггер надо делать корректно, чтобы не повесить сервер. К примеру, избегать зацикливания.

SergejKis: Посмотрел new letodb Changelog: 2011-04-18 19:30 UTC+0300 Pavel Tsarenko (tpe2/at/mail.ru) * source/client/leto1.c + letoGetRec and letoPutRec functions are implemented. Note, than deleted flag isn't included in record buffer * source/server/letofunc.c * Increased buffer size for LETO_INDEXINFO 2011-04-17 15:30 UTC+0300 Pavel Tsarenko (tpe2/at/mail.ru) * Changelog * updated previos entry * source/server/server.prg * Readme.txt * readme_rus.txt + added new options in letodb.ini: Trigger=<cFuncName> and PendingTrigger=<cFuncName>. When this options is set, global letodb functions is used as trigger by call HB_RddInfo( RDDI_TRIGGER, <cFunc> ) or HB_RddInfo( RDDI_PENDINGTRIGGER, <cFunc> ) Readme.txt, readme_rus.txt от 13.04.2011, а не от 17го. Все отлично !!! На радостях, в ночи, установил xHarbur, собрал старую версию letodb и свою leto2011, клиента на 2.0. Запустил и протесировал в 3G. Все работает! УРА! Появился и такой вопрос, при записи на сервер тестового U08.DBF(всего 1801 rec) с танзакциями получилось: - если в транзакции по 100 записей, то 1100 записей улетают быстро, а остальные так замедляются, что в итоге 130 секунд - если в транзакции по 10 записей, то все улетает за 29 секунд без замедлений При нескольких запусках все повторяется в пределах указанного времени. В чем секрет или как подбирать объем транзакции ? По поводу letoGetRec и letoPutRec. Можно ли с ними работать как в VO. В VO можно было работать так: cRecord := VoDbRecordGet() aStru := DBSTRUCT() nOffset := 1 // пропускаем признак удаления n := 10 // номер искомого поля FOR i := 1 TO n - 1; nOffset += aStru[i, DBS_LEN] NEXT cVal := SubStr(cRecord, nOffset, aStru[n,DBS_LEN]) или sele OUT VoDbRecordPut(SubStr(cRecord, 1, nOffset)) Еще предложение (реализованную в своем letodb) - работа с алиасными путями в DataPath. примерно так: letodb.ini ... [ALIAS] \BASE1\ = \BASE1\TEST\UCHET\ \BASE2\ = \BASE2\TEMP\AAAAA\ ... server.prg: STATIC FUNCTION _Alias2Path( cName, cPath ) LOCAL i,j STATIC aAls STATIC nAls IF nAls == NIL aAls := _ReadIni2Arr("letodb.ini", "ALIAS") nAls := len(aAls) RETURN ( nAls > 0 ) ENDIF j := upper(cName) FOR i := 1 TO nAls IF subs(j, 1, aAls[i,3]) == aAls[i,1] cPath := aAls[i,2] cName := subs(cName, aAls[i,3]+1) EXIT ENDIF NEXT RETURN cPath+cName и заменить cFileName := cDataPath + cName (или cBagName) на cFileName := _Alias2Path(cName, cDataPath) На клиенте можно писать: //ip:port/base1/aaa.dbf или //ip:port/base2/bbb.dbf

Pasha: SergejKis пишет: Появился и такой вопрос, при записи на сервер тестового U08.DBF(всего 1801 rec) с танзакциями получилось: - если в транзакции по 100 записей, то 1100 записей улетают быстро, а остальные так замедляются, что в итоге 130 секунд - если в транзакции по 10 записей, то все улетает за 29 секунд без замедлений При нескольких запусках все повторяется в пределах указанного времени. В чем секрет или как подбирать объем транзакции ? Сама транзакция накапливается на клиенте, и по commit вся отправляется на сервер Возможно, тормоза связаны с перевыделением памяти. Это предположение, которое надо проверить. Если это так, то можно выделять память блоками, и сделать настройну размера блока. Мне несколько дней назад захотелось посмотреть, насколько могуч letodb. Сделал транзакцию из полмиллиона записей. Сначала не получилось: оказалось, что поддерживалось 2**16 записей. Увеличил счетчик до 4 байт, и транзакция успешно выполнилась. Но тоже медленно.

Pasha: SergejKis пишет: По поводу letoGetRec и letoPutRec. Можно ли с ними работать как в VO. Да, можно, только сейчас в буфере записи rdd leto нет флага deleted Я "на коленке", прямо в форум, написал функции чтения/записи всей записи (тавтология получилась), и, естественно в них были ошибки. Вечером покажу отлаженные функции, они у меня дома

Pasha: Но для простого копирования записей намного эффективнее будет использование функций __dbCopy. __dbApp, __dbTrans, или соответствующих команд При этом копирование выполняет сам сервер, без пересылки данных на клиент и с клиента

SergejKis: Паша в xHb нет функциий hb_DateTime() и hb_TtoS(...), как быть с ними в триггерах на сервере ? При этом копирование выполняет сам сервер, без пересылки данных на клиент и с клиента Меня интересует ситуация: cS := letoRecGet() sele myCdx dbAppend() dbRecordPut(subs(cS,1,nOffset1)+str(Sum1,nLenSum1,nDecSum1)+str(Sum2,nLenSum2,nDecSum2)+subs(cS,nOffset2)) и наоборот cS := dbRecordGet() sele myLeto leto_BeginTransaktion() dbAppend() letoPutRec(subs(cS,1,nOffset1)+str(Sum1,nLenSum1,nDecSum1)+str(Sum2,nLenSum2,nDecSum2)+subs(cS,nOffset2)) FieldPut(1," ") // чтобы сработал триггер leto_CommitTransaction()

Pasha: letoGetRec и letoPutRec это не харбор-функции, а методы rdd, и вызывать их напрямую нельзя Надо вызывать dbGetRecord и dbPutRecord и для dbfcdx, и для leto. Но для dbfcdx буфер записи содержит флаг deleted, а для leto - нет, и это надо учитывать. Теперь по поводу триггера. Последовательность для leto будет такая: dbPutRecord вызовет letoPutRec, который поместит параметр в буфер записи на клиенте. По dbCommit или leto_CommitTransaction() он будет отправлен на сервер. Затем на сервере для каждого поля будет вызван метод dbfPutValue. Этот метод перед своей работой вызовет триггер EVENT_PUT, который должен вернуть .T. или .F.. Если .f. - то значение в поле записано не будет, если .t. - будет.

Pasha: Добавил в LETO_BEGINTRANSACTION() необязательный параметр - nBlockSize Его можно указать для большой транзакции. Это размер блока для выделения памяти под транзакцию Сейчас этот размер порядка 1К. Для небольшой транзакции этого достаточно. Во время большой транзакции ее буфер постоянно перевыделяется (увеличивается) на размер блока, при этом содержимое буфера переписывается в новый участок памяти, а оно все больше и больше, что и дает падение производительности. Если указать достаточно большой размер блока, то таких операций перевыделения надо намного меньше. Я вызвал LETO_BEGINTRANSACTION( 32768 ) и получил огромный рост скорости на клиенте.

Pasha: Вот обещанные функции: [pre]#pragma BEGINDUMP #include "hbapi.h" #include "hbapiitm.h" #include "hbapirdd.h" HB_FUNC( DBRECORDGET ) { AREAP pArea = ( AREAP ) hb_rddGetCurrentWorkAreaPointer(); PHB_ITEM pItem = hb_itemPutNI( NULL, 0 ); BYTE *pRec; if( pArea && (SELF_INFO( (AREAP) pArea, DBI_GETRECSIZE, pItem ) == SUCCESS) && ( SELF_GETREC( (AREAP) pArea, &pRec ) == SUCCESS ) ) { hb_retclen( pRec, hb_itemGetNI(pItem) ); } hb_itemRelease( pItem ); } HB_FUNC( DBRECORDPUT ) { AREAP pArea = ( AREAP ) hb_rddGetCurrentWorkAreaPointer(); PHB_ITEM pItem = hb_itemPutNI( NULL, 0 ); if( pArea && ISCHAR(1) && (SELF_INFO( (AREAP) pArea, DBI_GETRECSIZE, pItem ) == SUCCESS) && hb_parclen(1) >= hb_itemGetNI(pItem) ) { SELF_PUTREC( pArea, hb_parc(1) ); } hb_itemRelease( pItem ); } #pragma ENDDUMP[/pre]

SergejKis: Паша, большое спасибо за разъяснения, терпение и функции ! Буду пробовать.

SergejKis: Паша, выскочила такая штука: сборка 2011-04-19 19:00 UTC+0300 Pavel Tsarenko (tpe2/at/mail.ru) leto_db.c: leto1.c: Warning W8075 leto1.c 442: Suspicious pointer conversion in function leto_ConnectionNew Error E2451 leto1.c 1056: Undefined symbol 'Custom' in function ParseTagInfo Error E2451 leto1.c 4157: Undefined symbol 'Custom' in function letoOrderInfo Error E2451 leto1.c 4166: Undefined symbol 'Custom' in function letoOrderInfo *** 3 errors in Compile *** letomgmn.c: сборка 2011-04-13 20:45 UTC+0300 Pavel Tsarenko (tpe2/at/mail.ru) leto_db.c: leto1.c: Warning W8075 leto1.c 441: Suspicious pointer conversion in function leto_ConnectionNew letomgmn.c:

Pasha: Скачайте include\rddleto.h

SergejKis: Паша пишет: Скачайте include\rddleto.h Спасибо за подсказку. Запутался в версиях

SergejKis: Провел тесты dbRecordGet/dbRecordPut для CDX. Результаты: File: U08.DBF, Record Len: 2966, Fields count: 140, LastRec: 30000 Time: 43.86 - FieldGet/FieldPut Time: 39.45 - dbRecordGet/dbRecordPut Time: 36.69 - COPY all TO ... File: U09.DBF, Record Len: 798, Fields count: 84, LastRec: 100000 Time: 51.41 - FieldGet/FieldPut Time: 39.38 - dbRecordGet/dbRecordPut Time: 33.61 - COPY all TO ... Паша пишет Надо вызывать dbGetRecord и dbPutRecord и для dbfcdx, и для leto. Но для dbfcdx буфер записи содержит флаг deleted, а для leto - нет, и это надо учитывать. Как для leto надо учитывать флаг deleted ? sele myCDX cDel := subs(dbRecordGet(),1,1) dbRecordPut(cDel+leto->dbRecordGet()) и leto->dbRecordPut(subs(myCDX->dbRecordGet(), 2)) или как-то иначе ?

Pasha: SergejKis пишет: Как для leto надо учитывать флаг deleted ? Как обычно if f1->(Deleted()) f2->(dbDelete()) endif

leo: Планируется ли в Letodb реализовать SQL-Запросы?

alx_on: Выложил в CVS версию с MT Новое: 1. DbDrop( cTableFile, cIndexFile ) 2. DbExists( cTableFile, cIndexFile ) 3. DbRename( cTableFile, cIndexFile, cNewFile ) 4. Leto_FileRead( cFileName, nStart, nLen, @cBuf ) 5. Leto_FileWrite( cFileName, nStart, cBuf ) 6. Leto_MemoWrite( cFileName, cBuf ) 7. Leto_FileSize( cFileName ) 8. leto_directory( cDirSpec, [cAttr] ) leto_Udf() - пока не доработаны под текущую схему (нет функций выбора и закрытия таблицы) Доработки 1. В лог (при debug>0) пишется факт подключения и закрытия подключения 2. В ini новая настройка "Optimize = 1" - выключает flush (не сбрасывается принудительно кэш на диск для ускорения работы) 3. Установка фильтра - обработка в строке фильтра выражения с "FIELD->" (ранее приводило к выполнению фильтра на стороне клиента) 4. В ini новая настройка "debug = 10" 5. В ini новая настройка "tables_max = 1000" - перевыделение памяти приводит к GPF 6. В ini новая настройка "users_max = 150" - перевыделение памяти приводит к GPF Запуск под WIN в режиме службы cvs -z3 -d:ext:letodb.cvs.sourceforge.net:/cvsroot/letodb co -r rel-1-mt letodb Pasha leto_Sum() и Transaction - допилил

Pasha: Отлично, спасибо ! Я думаю, что старую ветку letodb можно оставить в том виде, в котором она есть сейчас, если кому-то надо собирать letodb как раньше, и развивать новую. Пока только успел собрать сервер и сконнектиться к нему, подробно еще не смотрел

alx_on: Pasha В теории можно, скорее всего, оставить совместимость серверной части с xHarbour. В части сетевой подсистемы вернуть старый мехнизм (hbip.c) - только открыт воспрос с его правильной работой с MT В части потоков - не знаю, xHarbour не использую Хотелось бы расширить и улучшить функционал letodb. Например: 1. интеграция части функционала hbnetio (частично сделано) - для работы по сети без костылей в виде smb (nfs и т.д.) 2. Улучшение отзывчивости (ADS пошустрее в некоторых случаях) 3. Полный перевод на C 4. Добавление оптимизированного фильтра (по типу AdsAOF) - может быть на основе временных индексов, формируемых и контролируемых серверной частью 5. Контроль версии клиента и сервера при подключении (иначе возникают проблемы при смене протокола) 6. Кто то хотел SQL (некая мечта)

Pasha: По поводу xHarbour. Он сейчас лежит и едва дышит. Конечно, ситуация может кардинально измениться, и так уже бывало, но не будем предсказателями. Посмотрим, как сообщество воспримет новую конфигурацию letodb. Тратить усилия на полумертвый проект не очень хочется. п.2 Надо улучшить буферизацию skip ? 3. Там осталось всего-то 4 функции, создание/открытие таблицы/индекса. Я в прошлом году даже начинал переписывать, но так и не сбросил на cvs. Конечно надо. 4. Еще подумаю 5. Сложновато будет. Это на клиенте придется поддерживать все старые команды вместе с новыми, даже если в протоколе были незначительные изменения. 6. А почему бы и не сделать sql ? Парсер сделать на сервере на Харборе как класс. Группировочные запросы сделать с помощью hbtmemio Я когда-то собирался сделать в leto серверные relations. Но если будет sql, это уже будет не нужно. Кстати, раз уж сервер теперь можно смело нагружать тяжелыми операциями, хочу по аналогии с leto_sum добавить leto_GroupBy(xKeyField, cFields, [ cFilter ], [xScope], [xScopeBottom]) которая возвращала бы массив вида { { xKey1, nSum1, ...}, { xKey2, nSum2, ...}, ... } Думаю, надо делать sql



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