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

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

КСС: А NTX-ы поддерживает ? А программный код дорабатывать нужно и насколько ? А то у меня есть задачка на Clipper-е, которая реально работает 10 лет в сети, и нагрузка приличная. Можно было бы потестировать, да и быстродействие сравнить.

Pasha: Добавьте меня, пожалуйста Мой account на sourceforge - ptsarenko Кстати, где собираетесь вести обсуждение проекта ? Будут ведь не только русскоязычные разработчики

alkresin: Прямо сейчас ntx не поддерживает, хотя добавить это дело не сложно - просто сам уже много лет ntx'ами не пользуюсь и не понимаю зачем они нужны, если есть cdx :). Но раз есть спрос - добавлю.


alkresin: Мой account на sourceforge - ptsarenko Добавил. Кстати, где собираетесь вести обсуждение проекта ? Будут ведь не только русскоязычные разработчики Да на том же Sourceforge - там 3 форума по умолчанию открыто. И mail list можно там же запустить, если нужда будет.

alkresin: КСС пишет: А программный код дорабатывать нужно и насколько ? Нет, просто как обычно вставить строчки для этого RDD: REQUEST LETO RDDSETDEFAULT( "LETO" ) Ну и, конечно, пути указать с учетом пути к серверу, например: //192.168.5.3:2812/data/mydir

Andrey: alkresin пишет: Кто хочет участвовать в разработке, тестировании - пишите. Я хочу, мой е-майл: 30195@mail.ru Если этот сервер сравним с ADS (мне транзакции не нужны) и переделка программ минимально, то я готов потратить деньги предприятия на него (для ADS-денег нет, тогда пускай родного разработчика поддержат). У меня стоит остро вопрос разгрузки файл-сервера. 15-16 рабочих мест (каждый юзер запускает 2-3 мои задачи [~180-файлов в каждой] и еще штук 8-10 докуменов одновременно) и 2-х ядерный P4 начинает тормозить.

Pasha: Сделал небольшие изменения для сборки под xharbour Александр, подскажите, что это может быть и где копать Соединяюсь локально, WinXP Сначала пытаюсь создать файл: Local cFile := '//127.0.0.1:2812/e/hb/test/_first' dbCreate(cFile, {{'STR', 'C', 20, 0}}) выдается ошибка Error LETO/1021 Data type error: -011:20 при открытии тоже: dbUseArea(.t.,, '//127.0.0.1:2812/e/hb/test/account') Error LETO/1021 Data type error: -003:21

Andrey: Pasha пишет: Сделал небольшие изменения для сборки под xharbour А у меня не собирается под хХарбором ! Подскажи пожалуйста где и что править (я не слишком силен в этом)....

Pasha: Что за ошибка при сборке ? Если на HB_FT_IMAGE, это значит, что обновление на CVS еще недоступно. Обновись еще раз, Changelog должен быть 1.2

Pasha: Changelog уже 1.3 Александр, на use и dbCreate у меня остались ошибки

alkresin: Касательно возвращаемого кода ( 003:21, 011:20 ) - это временная система для обозначения ошибок. Если стоит вот такое, это значит, что после двоеточия - стандартный код ошибки при выполнении операции на сервере, описанный в error.ch В нашем случае - 20 - EG_CREATE, 21 - EG_OPEN, что не очень информативно :). А e/ у вас в пути - это каталог ?

alkresin: Andrey пишет: А у меня не собирается под хХарбором ! Подскажи пожалуйста где и что править (я не слишком силен в этом).... Изменения, сделанные Pasha, отправил по email. Надо будет новый build сделать.

Pasha: Это диск. Кстати, как надо указывать каталог с диском для win-сервера ? А как быть, если нет статического IP-адреса сервера ? если указать dbUseArea(.t.,, '//servername:2812/e/letodb/test') Выдается ошибка 101 Я конечно подсмотрел адрес через ping, поставил: dbUseArea(.t.,, '//192.168.0.216:2812/e/letodb/test') Но все равно Выдается ошибка 101 Т.е. ругается функция leto_getIpFromPath, не может выделить адрес 192.168.0.216

Pasha: alkresin пишет: Надо будет новый build сделать. Может быть, выкладывать собранные letodb.exe и letodb.lib прямо на sourceforge, для тех, кто не скачивает с CVS ?

alkresin: Это диск. Кстати, как надо указывать каталог с диском для win-сервера ? Вот поэтому и ошибка. Весь путь, начиная с '/' после номера порта передается на сервер, сервер добавляет его к содержимому "DataPath", прописанному в ini - файле ( если есть ) и использует для открытия файла. Поэтому, если обязательно нужен диск, попробуйте форму //127.0.0.1:2812/e:/hb/test/_first, а лучше - пропишите в letodb.ini DataPath = e:/hb и тогда при открытии: //127.0.0.1:2812/test/_first По поводу имени вместо ip я проверю

alkresin: Может быть, выкладывать собранные letodb.exe и letodb.lib прямо на sourceforge, для тех, кто не скачивает с CVS ? Исходники там выложены в секции Download. Бинарник сервера тоже можно выложить, а вот rddleto.lib - не вижу смысла, потому что тогда придется кучу их выкладывать, для разных С и Харбор компиляторов, их версий

alkresin: С адресами как ваш 192.168.0.216, действительно, глупая ошибка была в leto_getIpFromPath() - уже поправил на CVS

Vlad04: Хочу принять участие в тестировании . orsv04@mail.ru

Andrey: Блин, никак не могу найти исправления, вижу только letodb-0.1.src.zip Mirror 56682 0 Platform-Independent Source .zip Или я что-то не догоняю ?

alkresin: На email же отправил

Pasha: Ура ! Есть первый коннект Для windows-сервера: letodb.ini (должен быть на сервере) DataPath = e:/hb/test Должен быть прямой слеш соединяюсь: dbUseArea(.t.,, '//127.0.0.1:2812/test') Но выплыла еще ошибка: ? FieldPos('First') Выдает 1 А обращение по имени поля: ? First Переменная не существует First Если указать: ? Field->First То все нормально Вроде бы rdd тут ни при чем Или я что-то не понимаю, или это какая-то особенность harbour (я тестирую пока с ним, до xHb дело еще не дошло)

alkresin: Хочу принять участие в тестировании . orsv04@mail.ru Ну, email для этого не нужен. Лучше всего, забирай исходники с CVS - это нетрудно или подожди чуть - я исправленный zip выложу на Sourceforge как build2

alkresin: А обращение по имени поля: ? First Переменная не существует First Если указать: ? Field->First То все нормально Странно, я всегда именно так и указываю, без field->

alkresin: Проверь тот же тест с dbfcdx, без сервера

Andrey: alkresin пишет: На email же отправил Получил, тоже не собирается.

Pasha: Какая ошибка ? Что в make_b32.log ?

Andrey: Pasha пишет: Что в make_b32.log ? MAKE Version 5.2 Copyright (c) 1987, 2000 Borland bcc32 -c -Iinclude;Z:\xHarbour\include -d -D__WIN32__ -oobj\b32\leto1.obj source\client\leto1.c Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland source\client\leto1.c: Warning W8065 source\client\leto1.c 336: Call to function 'leto_NetName' with no prototype in function leto_ConnectionNew Warning W8069 source\client\leto1.c 336: Nonportable pointer conversion in function leto_ConnectionNew Warning W8004 source\client\leto1.c 1162: 'ptr' is assigned a value that is never used in function letoPutValue Warning W8065 source\client\leto1.c 1383: Call to function 'hb_setGetCPtr' with no prototype in function letoCreate Error E2342 source\client\leto1.c 1383: Type mismatch in parameter 'sSource' (wanted 'signed char *', got 'int') in function letoCreate Warning W8065 source\client\leto1.c 1541: Call to function 'hb_setGetCPtr' with no prototype in function letoOpen Error E2342 source\client\leto1.c 1541: Type mismatch in parameter 'sSource' (wanted 'signed char *', got 'int') in function letoOpen Error E2451 source\client\leto1.c 1639: Undefined symbol 'uiFlags' in function letoOpen Warning W8057 source\client\leto1.c 1812: Parameter 'pOrderInfo' is never used in function letoOrderListAdd Warning W8057 source\client\leto1.c 1834: Parameter 'pOrderInfo' is never used in function letoOrderListDelete Warning W8057 source\client\leto1.c 2009: Parameter 'pOrderInfo' is never used in function letoOrderDestroy *** 3 errors in Compile *** ** error 1 ** deleting obj\b32\leto1.obj

Pasha: alkresin пишет: Проверь тот же тест с dbfcdx, без сервера Та же ошибка. Вопрос снят. Наверное, дело в ключах компилятора

Pasha: Andrey пишет: MAKE Version 5.2 Copyright (c) 1987, 2000 Borland bcc32 -c -Iinclude;Z:\xHarbour\include -d -D__WIN32__ -oobj\b32\leto1.obj source\client\leto1.c Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland source\client\leto1.c: Warning W8065 source\client\leto1.c 336: Call to function 'leto_NetName' with no prototype in function leto_ConnectionNew Это было в первоначальном варианте, исправлено еще вчера

Pasha: А, дошло В makefile.bc сними комментарий со строки # XHARBOUR = yes

Vlad04: Может быть, выкладывать собранные letodb.exe и letodb.lib прямо на sourceforge, для тех, кто не скачивает с CVS САМОЕ оптимальное

Andrey: Pasha пишет: В makefile.bc сними комментарий со строки # XHARBOUR = yes Нет там такой строчки, вообще !!!

Pasha: Значит, у тебя старые сырцы

Andrey: Pasha пишет: Значит, у тебя старые сырцы А где взять новые ? Там только: letodb-0.1.src.zip Mirror 56682 0 Platform-Independent Source .zip

alkresin: Сделал еще одно исправление, теперь можно и по имени сервер называть: use //MYSERVER:2812/data/test.dbf

alkresin: Андрей, опять выслал по email patch.zip

alkresin: Vlad04, вопрос в том, какую именно rddleto.lib выкладывать, их же может быть много разных - для Harbour, xHarbour, WIndows, Linux, Borland C, MS Visual C и пр. С компиляторы, посчитайте число возможных комбинаций :). Поэтому проще выложить исходники - одни на все случаи жизни.

alkresin: Changelog'и постим в https://sourceforge.net/forum/forum.php?forum_id=779825 - форум "Developers" на Sourceforge.

alkresin: Проверил я его сегодня на "старых" версиях [x]Harbour - до ноября 2007 и обнаружил, что с ними есть проблемы. Буду разбираться, а пока, если у вас Harbour не с CVS, не торопитесь тестировать.

alkresin: Теперь работает и на "старых" версиях, изменения выложены на CVS

Pasha: Александр, не могу разобраться При открытии таблицы под xHb на клиенте в leto1.c leto_ParseRec после строки 401 на pField = pArea->lpFields; происходит gpf при любом обращении к pField->any, такое впечатление, что память не выделена под pArea->lpFields. xHarbour с CVS. Еще одна мелочь. В console.prg замените ExeName() на HB_Argv(0), чтобы не прилинковывать тулз. Я сам не стал, по changelog увидел, что модуль обновлялся сегодня, а у меня еще версии 1.1

alkresin: Память под pArea->lpFields выделяется в верхнем слое RDD - workarea.c, hb_waSetFieldExtent() ( вызов SELF_SETFIELDEXTENT из letoOpen() ). Она может быть не выделена, если в вызове SELF_SETFIELDEXTENT стоит 0 полей - это может произойти, если неправильно интерпретированы данные с сервера. А может случиться, что память была выделена, но потом значение указателя чем-то затерто.

Pasha: Выяснил, что gpf возникает только на xHb CVS, на старой (июльской) весии ок Делаю scope, еще не постил. Передаю команду на сервер, и на сервере отрабатываю DBOI_SCOPETOP, DBOI_SCOPETOPCLEAR итд. Это правильный подход ? Еще не сбрасывал на CVS, проверяю Как лучше делать DBOI_KEYVAL ? Вычислять на клиенте или запрашивать с сервера ? Для DBOI_KEYSIZE думаю добавить еже один элемент в LETOTAGINFO. Правильно ? Увидел такую несовместимость. После OrdListAdd() в dbfdcx автотматически устанавливается 1-й индекс, а в letodb надо еще выдавать dbSetOrder(1)

alkresin: Нашел, в чем проблема со свежим xHarbour. Вот она: 2008-01-10 11:47 UTC+0100 Miguel Angel Marchuet <miguelangel/at/marchuet.net> Он изменил базовую структуру rdd AREA, зараза! А в каждом RDD ( в т.ч. и у нас - rddleto.h ) эта структура дублируется, и в конце добавляются специфичные для этого RDD поля. Что с этим делать, чтоб с предыдущими версиями xHarbour использовалась старая структура, а с новейшей - новая, я пока не знаю. Делаю scope, еще не постил. Передаю команду на сервер, и на сервере отрабатываю DBOI_SCOPETOP, DBOI_SCOPETOPCLEAR итд. Это правильный подход В принципе, да, но этого недостаточно. Учти, что на сервере открывается одна копия таблицы для всех, и если ты установишь там scope, то он и у других пользователей, использующих эту таблицу, появится - представляю себе их удивление :). Как лучше делать DBOI_KEYVAL ? Вычислять на клиенте или запрашивать с сервера ? На клиенте. Все, что можно, надо делать на клиенте, чтоб не загружать сервер лишней работой. Для DBOI_KEYSIZE думаю добавить еже один элемент в LETOTAGINFO. Правильно ? Угу.

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

Pasha: alkresin пишет: Нашел, в чем проблема со свежим xHarbour. Вот она: 2008-01-10 11:47 UTC+0100 Miguel Angel Marchuet <miguelangel/at/marchuet.net> Он изменил базовую структуру rdd AREA, зараза! Я из-за этого не спешу использовать свежие сырцы. Появляются несоотсвествия с прежней структуроой заголовкка. Раньше допускались произвольные значения в резервных полях, а сейчас - результат непредсказуемый

alkresin: Не было там резервных полей. Он вставил новое поле до lpfields и 2 - после. Поэтому workarea.c присваивает значение lpfields, а у нас оно попадает в другое место, lpfields остается неинициализированным. И дело не в том, свежие сырцы или нет. Если б он это не сейчас сделал, а 3 месяца назад, какая разница ? Все равно - с одной версией работало б, с другой - нет. Придется, наверное, 2 экземпляра rddleto.h держать и примечание оставить для пользователей xHarbour > 10.01.08, чтоб переименовывали свое xrddleto.h в rddleto.h ...

Pasha: Добавил scope

Pasha: Добавил OrdKeyVal()

Pasha: Александр, я столкнулся с необходимостью проверять существование файла на сервере. Например, если есть файл cdx - открывать его, если нет - индексировать Сделал отдельный модуль на клиенте: letomgmt.c: #include "hbapi.h" #include "rddleto.h" int leto_getIpFromPath( char * sSource, char * szAddr, int * piPort, char * szPath ); LETOCONNECTION * leto_ConnectionFind( char * szAddr, int iPort ); LETOCONNECTION * leto_ConnectionNew( char * szAddr, int iPort ); long int leto_Recv( HB_SOCKET_T hSocket ); char * leto_firstchar( void ); int leto_getCmdItem( char ** pptr, char * szDest ); static int leto_DataSendRecv( LETOCONNECTION * pConnection, char * sData, ULONG ulLen ) { if ( hb_ipSend( pConnection->hSocket, sData, (ulLen)? ulLen:strlen(sData), -1, 1 ) <= 0 ) { return 0; } return leto_Recv( pConnection->hSocket ); } HB_FUNC( LETO_FILE ) { LETOCONNECTION * pConnection; char szFile[_POSIX_PATH_MAX + 1]; char szAddr[96]; int iPort; if( ISCHAR(1) && leto_getIpFromPath( hb_parc(1), szAddr, &iPort, szFile ) && ( ( pConnection = leto_ConnectionFind( szAddr, iPort ) ) || ( pConnection = leto_ConnectionNew( szAddr, iPort) ) ) ) { char szData[_POSIX_PATH_MAX + 16]; sprintf( szData,"file;%s;\r\n", szFile ); if ( !leto_DataSendRecv( pConnection, szData, 0 ) ) { hb_retl( FALSE ); } else { char * ptr = leto_firstchar(); leto_getCmdItem( &ptr, szData ); ptr ++; hb_retl( szData[0] == 'T' ); } } else hb_retl( FALSE ); } снял static с используемых функций в leto1.c. Чтобы не добавлять LETO_FILE к rdd. Ok ? Или организовать клиентскую библиотеку по другому ? Сейчас отлаживаю на сервере написал: ELSEIF cItem == "file" cReply := hs_file( oUser,Substr(cCommand,nPos1+1) ) ... Function hs_file( oUser,cCommand ) Local cFile, nPos := 1 IF Empty( cFile := GetCmdItem( cCommand,nPos,@nPos ) ) Return "-002" ENDIF Return "+" + File(oApp:DataPath+cFile) Вообще, хорошо бы для сервера windows, да и для самбы сделать поиск IP-адреса по сетевому пути, если подключен сетевой диск. Это возможно ? Было бы как в ADS В целом, получается неплохо. И интернет-сервер (аналог AIS), и сервер по ЛВС в одном флаконе

Pasha: Добавил LETO_FILE() - аналог File(), а также обработку OrdBugExt() и OrdNumber()

alkresin: Отлично! Я сам планировал эту функцию сделать, а, может, и другие файловые - в ADS мне их сильно не хватало. Вот только static int leto_DataSendRecv() по-моему, не стоило делать, надо использовать ту, что есть из leto1.c - избегаем дублирования кода и, главное, желательно, чтобы все функции, работающие непосредственно с сокетом, были собраны в одном месте - легче потом менять в случае чего. И насчет scope - я считаю, что нет нужды возвращать тип и значение scope с сервера, все это прекрасно клиент сам может определить, зачем же сервер зря утруждать ... Вообще, хорошо бы для сервера windows, да и для самбы сделать поиск IP-адреса по сетевому пути, если подключен сетевой диск. Это возможно ? Сделать то можно, раз ADS смогли :), но не знаю как. И, вообще-то, считаю это ненужным и даже вредным с точки зрения безопасности данных. Все известные мне DBMS используют имя сервера/ip, порт, имя базы и таблиц, для доступа к данным, а где именно хранится база, пользователь не знает и знать не должен - это важное преимущество подобных систем. У тебя никогда не случалось, что пользователь случайно удалял данные с сервера, просто щелкая мышкой по окну файлового менеджера ? У меня было ... Поэтому важно, чтобы каталог с данными не был расшарен - и то, что наш сервер позволяет скрыть данные, я считаю существенным преимуществом. А ADS позволяет это в силу исторических причин, он ведь начинался с версии для Novell 3.12 и IPX протокола.

Pasha: alkresin пишет: Вот только static int leto_DataSendRecv() по-моему, не стоило делать, надо использовать ту, что есть из leto1.c - избегаем дублирования кода и, главное, желательно, чтобы все функции, работающие непосредственно с сокетом, были собраны в одном месте - легче потом менять в случае чего. И насчет scope - я считаю, что нет нужды возвращать тип и значение scope с сервера, все это прекрасно клиент сам может определить, зачем же сервер зря утруждать ... ok, переделаю

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

alkresin: Да, Pasha, поставь на letomgmn.c свой копирайт - ты же его original author.

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

alkresin: В смысле, названия переменных и полей db - на русском, или что-то еще ?

Pasha: alkresin пишет: В смысле, названия переменных и полей db - на русском, или что-то еще ? Да, и не более того. Сейчас на такие идентификаторы компилятор выдаст ошибку Leto. По поводу StoredProc: мысль такая. Подготовить модуль в виде hrb-файла на сервере По команде с клиента загружать-выгружать его. Отдельная команда на вызов функции из этого модуля с передачей параметров и возвратом результата На сервере перед вызовом функции из hrb устанавливать все окружение каждой открытой РО для этого пользователя: номер записи, фильтр итд. Запоминать это состояние. После отработки функции передавать на клиент кроме результата еще и новое состояние изменившихся РО. На клиенте его отрабатываеть Какие будут идеи ? Кстати, Pritpal Bedi не говорил, чем он собирается заниматься ? Чтобы мы не делали одно и тоже. Я, к примеру, думаю начать делать relations

Pasha: Только алиасы РО на сервере и на клиенте будут отличаться. Нужна будет функция для получения истинного алиаса

alkresin: Да, и не более того. Сейчас на такие идентификаторы компилятор выдаст ошибку Ну что тут сказать ... Если кто-то заинтересован в таком локализованном компиляторе, пусть делает. Подними этот вопрос в developer'ском листе - может, кто заинтересуется. Лично я как-то привык уже, что имена переменных, команд, функций - на английском, мне это кажется удобным - легко отличать их от текстовых строк на русском. А программа с русскими идентификаторами показалась бы, пожалуй, неудобочитаемой... С полями в база вопрос еще интереснее - тогда ведь программы на других xBase диалектах не смогут открыть такой файл. Я бы такими средствами локализации не пользовался. По stored procedures надо еще подумать. Может, стоит восстанавливать состояние РО после выполнения ? Сначала, мне кажется, надо реализовать схему запуска процессов и межпроцессного взаимодействия - мы же не будем выполнять их основным процессом, они могут быть достаточно длительными. Значит, загружать/выгружать hrb будет как раз тот дополнительный процесс. О намерениях Pritpal Bedi ничего не знаю, он со мной после запроса write access не контактировал. Сегодня, кстати, обратился Miguel Angel Marchuet ( он сейчас один из основных контрибуторов в xHarbour ? ) - я его сразу озадачил той проблемой с изменением workarea :). По алиасам - это предусмотрено: имя алиаса, как его знает клиент, передается из letoOpen() сразу после имени файла - т.е., должно передаваться, сейчас там пустая строка. И на сервере оно читается, но никак не используется. Надо будет создать HSArea:cAlias и присвоить ему это значение.

Pasha: Переделал scope, отправил на CVS Одну свою большую программу с letodb так и не смог запустить, не открывается 5-й по порядку открытия файл. Непонятно почему, имя задано правильно. 4 файла БД с индексом открылись успешно Ошибка в лог: 02/04/08 19:14:46: Open error (12-1001): e:/db/test/com/people_ Если вместо people_.dbf путаюсь открыть другой файл, выдается ошибка с таким же кодом Непонятно. Пока отставил, запустил другую программу. БД открылась успешно ! Большинство режимов работают, но не все Иногда программа зависает, иногда выдает ошибку на различных операциях Пока не локализовал, разбираюсь. Результат считаю хорошим, я на это так быстро и не расчитывал Пока тестовые примеры c ошибками не даю, попытаюсь разобраться сам

alkresin: 02/04/08 19:14:46: Open error (12-1001): e:/db/test/com/people_ А точно 12-1001 ? Может, 21-1001 ? Ведь 12 == EG_NOFUNC, вроде ни при чем ? А вообще странно. У меня никаких проблем нет, все программы, что скомпилил - работают, файлов по 10 открывают ( у меня больше не бывает обычно ).

Pasha: Я скопировл из лога. Покопаюсь сам, странная ситуация У меня тоже другая программа всю БД без проблем открыла Одну ошибку локализовал dbSeek(space(n)) попадает в server.prg на IF Empty( xKey := GetCmdItem( cCommand,nPos+1,@nPos ) ) Return "-002" ENDIF Надо вычислять длину ключа и передавать ее вместе с ключем. И учитывать, что сам ключ может содержать нулевой байт. Т.е в leto_SendRecv надо передавать размер пакета напрямую, а не вычислять по strlen()

Pasha: Как правильно создавать индекс в OrdCreate, если его надо создать в том же каталоге, что и dbf ? Передавать имя файла индекса без //ip-adr:port/... ? Должна ли учитываться настройка DataPath в letodb.ini ? Наверное, надо добавить oApp:DataPath в hs_createindex ordCreate( oApp:DataPath+cBagName,cTagName,cKey,&("{||"+cKey+"}"),lUnique )

alkresin: Надо вычислять длину ключа и передавать ее вместе с ключем. И учитывать, что сам ключ может содержать нулевой байт. Т.е в leto_SendRecv надо передавать размер пакета напрямую, а не вычислять по strlen() Сделаю. Насчет OrdCreate: //ip-adr:port/ и так на сервер не передается. Если имя индекса передано с путем, то надо добавлять oApp:DataPath, если без, то нужна дополнительная проверка: если имя индекса совпадает с именем dbf, то не добавляем oApp:DataPath ( он автоматически размещается там же, где и dbf ), если другое имя - то добавляем.

Pasha: Ясно Александр, а как насчет создания вычисляемых readonly полей ? CalcFields дали бы существенное сокращение траффика для случая, когда в основной таблице содержится код (например) справочника, и надо выбрать его наименование Такое есть в sql-запросах, но до них еще далеко. Такие выборки эффективнее, чем relations, так как будет использоваться данные одной, а не 2-х РО, без лишних seek и выборки данных записи Это были бы ф-ии вида: AddCalcField(cFieldName, cFieldType, nLen, nDec, cAlias, cKeyExpr, cRelField) динамически добавляет поле DelCalcField(cFieldName) удаляет

alkresin: Хм... Виртуальное поле, вычисляемое на сервере из логически связанных таблиц ? Очень интересная идея. Мне нравится.

Pasha: Ну да Примерно такое есть в Delphi-TDataset, правда там оно не вычисляется на сервере

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

alkresin: http://www.letodb.org/ - Спасибо Патрику ( Patrick Mast )

alkresin: Предполагаемые направления работы: 1) Тестирование, тестирование, тестирование ... 2) Проверить, что еще осталось не сделанным из базовых функций - и сделать. Первые претенденты - ordListAdd, ordListClear, ordListDelete - после них можно будет сделать поддержку ntx. Ну и relations, конечно. 3) Насколько это возможно и целесообразно, код сервера должен быть переписан на C, особенно вот это : IF cItem == "skip" ... ELSEIF cItem == "seek" ... 4) Процессы и, возможно, потоки. Я подумал, что можно было бы реализовать потоки на уровне С - это должно быть не сложным, и тогда можно будет разгрузить основной поток, передав туда, например, посылку ответов. 5) С использованием процессов и потоков - реализация транзакций, stored procedures, ... 6) Ну и расширения разные, типа вот этих виртуальных полей

Петр: Судя по всему авторизация, и все с ней связанное, в LetoDB не предполагается ?

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

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

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

Pasha: alkresin пишет: 4) Процессы и, возможно, потоки. Я подумал, что можно было бы реализовать потоки на уровне С - это должно быть не сложным, и тогда можно будет разгрузить основной поток, передав туда, например, посылку ответов. А какими средствами, если не использовать mt xHb ? Тем более, надо расчитывать и на unix, и на windows - сервер

alkresin: Pasha, я скинул на CVS изменения, чтоб работало со свежим xHarbour, не мог бы проверить ?

Pasha: alkresin пишет: после них можно будет сделать поддержку ntx. Отдельные rdd выделять не будем ? Сделать что-то вроде LetoConnection(...), и в качестве параметра - используемый rdd ? Еще необходимы Request на используемые кодовые страницы, но это еще на этапе сборки сервера

alkresin: А какими средствами, если не использовать mt xHb ? Тем более, надо расчитывать и на unix, и на windows - сервер Написать. В xHarbour эти средства большие и сложные, потому что надо было обеспечить корректную работу vm, стека и пр. в условиях mt. Здесь же можно сделать запуск потока только на С уровне, чтобы функция, работающая в этом потоке, не трогала Харборовский стек. Мне кажется, что это не особенно трудоемкое дело.

Pasha: alkresin пишет: Pasha, я скинул на CVS изменения, чтоб работало со свежим xHarbour, не мог бы проверить ? Я с работы на CVS не достучусь. Разве что через browse cvs скачивать Вечером получу только. Это для текущих сырцов, как я понимаю ?

alkresin: Отдельные rdd выделять не будем ? Сделать что-то вроде LetoConnection(...), и в качестве параметра - используемый rdd ? Название rdd, думаю, должно передаваться при открытии файла. Может ведь программа работать и с ntx и с cdx, находящимися на одном сервере ( одном соединении ).

alkresin: Это для текущих сырцов, как я понимаю ? Да.

alkresin: К разговору о перспективах: очень заманчиво выглядит возможность использовать это дело для доступа к данным на сервере с мобильного устройства ( КПК, смартфона ). У ADS нет ведь клиентских библиотек для доступа с их серверу, а у нас теперь есть. Лежишь на пляже и проверяешь, сколько тебе зарплаты начислили :), или добавляшь запись в специальную таблицу, а stored proc ее обрабатывает и предпринимает соответствующие действия, например, сообщения рассылает.

Pasha: Сделать харбор для symbian, что ли ? :)

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

alkresin: Сделать харбор для symbian, что ли ? Харбор уже работает на мобильных устройствах под Windows Mobile. Просто прилинковать Leto RDD и - вперед. Хотя, конечно, надо еще проверить, как оно будет работать с Интернет - соединением.

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

Петр: alkresin пишет: о, с другой стороны, stored proc ведь не любой пользователь помещает, а администратор, он должен знать, что делает Да, но сервер должен знать, что он именно с администратором общается

alkresin: Это если помещать через клиентскую программу и RDD. А если их может разместить только администратор руками на сервере, а клиент может только запустить на исполнение по имени - это уже другая ситуация.

Pasha: alkresin пишет: Pasha, я скинул на CVS изменения, чтоб работало со свежим xHarbour, не мог бы проверить ? Все заработало

alkresin: Отлично! Значит, можно build2 делать.

Pasha: Какая-то проблема с блокировками select order dbAppend() Field->Type:='01' dbcommit() dbunlock() rlock() Field->Stock:='01' dbcommit() dbunlock() вываливается на 2-м коммите Ошибка LETO/1021 Data type error: -015 Алиас ORDER Вызов из DBCOMMIT(0)

Pasha: Разобрался я с мистическим 5-м файлом :) В индексном выражении было обращение к StrZero. А к серверу эта функция не подлинкована. Добавил Request С этим надо что-то делать. Нужен какой-то джентльменский набор функций. Можно хотя бы взять из описания Ads список поддерживаемых функций, да и еще добавить своих, харборовских :)

Pasha: Такой набор функций Request ; ABS,; ALLTRIM,; AT,; CHR,; CTOD,; DATE,; DAY,; DELETED,; DESCEND,; DTOC,; DTOS,; EMPTY,; I2BIN,; L2BIN,; LEFT,; LEN,; LOWER,; LTRIM,; MAX,; MIN,; MONTH,; PAD,; PADC,; PADL,; PADR,; RAT,; RECNO,; RIGHT,; ROUND,; RTRIM,; SPACE,; STOD,; STR,; STRZERO,; SUBSTR,; TIME,; TRANSFORM,; TRIM,; UPPER,; VAL,; YEAR И специфика Ads /* Ads-specific functions Request ; CONTAINS,; COLLATE,; CTOT,; CTOTS,; LOWERW,; NOW,; REVERSE,; STOTS,; TODAY,; TSTOD,; UPPERW */ Добавляем ?

alkresin: Какая-то проблема с блокировками Исправил. Добавляем ? Добавляем.

Pasha: Seek ведет себя по-другому Если тип ключа не совпадает с типом индекса, то dbfcdx просто возвращает .f., а letodb поднимает ошибку

Pasha: теперь с блокировками порядок

Pasha: На сегодня я иссяк :) Список багов исчерпан

Andrey: alkresin пишет: чтоб работало со свежим xHarbour, не мог бы проверить ? Я хочу проверить, но так и не собрал ничего на хХарборе ! Сам ехе-ник letodb.exe собрался, а из папки "manager" не собирается, требует библиотеку 'HBCT.LIB' и сборка сама для HARBOUR'a ...

alkresin: Небольшая инструкция по использованию ( по просьбе Андрея ). 1) Сервер предназначен для работы c dbf/cdx файлами ( ntx тоже добавим ), расположенными на севере в локальной сети или Интернете. На своем локальном компьютере его имеет смысл использовать только для проверки и отладки. 2) Чтобы запустить сервер, просто запустите letodb.exe ( letodb - в Linux ) из того каталога, который вы для него выберите. После запуска сервер не создает окна, а просто размещается в памяти, при этом создается запись в letodb.log, расположенном по умолчанию в каталоге, откуда сервер запущен. В этот же лог пишутся сообщения об остановке сервера, о проблемах при открытии/создании dbf, и аварийные сообщения, если сервер вдруг слетит ( не должен :) ). Останавливается сервер командой letodb.exe stop. 3) При необходимости можно создать файл letodb.ini в каталоге запуска сервера ( под Linux - можно еще в /etc ). В настоящее время поддерживаются следующие опции (указаны значения по умолчанию): Port = 2812 - номер порта DataPath = - каталог с базами Log = letodb.ini - путь и имя журнала Lower_Path = 0 - для Linux, 1 - если надо переводить пути и имена файлов в нижний регистр. Если указан DataPath, то он будет добавляться к пути при открытии файла. Например, DataPath = d:\data a открываете файл вы командой USE "192.168.3.5:2812/dbsklad/test" В этом случае сервер будет открывать файл d:\data\dbsklad\test.dbf 4) Чтобы скомпилировать вашу программу для работы с Leto db, надо: a) добавить в список библиотек rddleto.lib b) добавить в программу 2 строчки: REQUEST LETO RDDSETDEFAULT( "LETO" ) в) откорректировать пути к базам с учетом имени/ip сервера и порта. Если у вас в программах пути задаются где-то в одном месте, лучше - в ini файле или в параметрах, передаваемых программе, это сделать легко и просто. В идеальном случае после этого ваша программа должна заработать с Leto db сервером ( у меня почти сразу так и получилось ), в реальном - возможны проблемы, т.к. не все функции еще реализованы. 5) Если вы запустили сервер на локальном компьютере, то путь должен быть: //127.0.0.1:2812/... 6) По утилитам в каталоге utils/manage: bld.bat предназначен для компиляции manage.prg - GUI утилита, для сборки нужен HwGUI. Консольная утилита console.prg собирается вашими стандартными средствами, которыми вы собираете свои одно-файловые программы, надо только добавить rddleto.lib в список библиотек.

alkresin: Выложил на Sourceforge build2 - поправлены все несовместимости с разными версиями Harbour/xHarbour, поисправлены некоторые ошибки, добавлены некоторые базовые функции.

Петр: Andrey пишет: и сборка сама для HARBOUR'a Здесь можно поспорить По крайней мере названия библиотек не согласуются с Harbour SVN. Но это же не проблема - поменять название библиотеки, добавить или удалить что-то..

Andrey: Andrey пишет: Сам ехе-ник letodb.exe собрался, а из папки "manager" не собирается, требует библиотеку 'HBCT.LIB' и сборка сама для HARBOUR'a ... Так где ж ее взять ???

alkresin: В xHarbour она называется ct.lib - надо исправить в bld.bat

Andrey: Понял, спасибо ! Только я в Harbour'e не нашел HBCT. Хотя он у меня свежий.

Петр: Andrey, я так думаю, что тестировать нужно сервер, не manager. Тем более у тебя такие планы были..

Петр: Harbour библиотека HBCT находится в contrib.

Andrey: alkresin пишет: Log = letodb.ini - путь и имя журнала Поправочка ! Строка должна иметь вид: Log = letodb.log

alkresin: Понял, спасибо ! Только я в Harbour'e не нашел HBCT. Хотя он у меня свежий. Свежий - это откуда ? C SVN ? Строил из исходников ? Тогда чтоб построить hbct.lib, надо зайти в contrib/hbct и там запустить make_32.bat

gfilatov: Andrey пишет: Так где ж ее взять ? Выложил готовую к использованию сборку LetoDB по адресу: http://minigui.mylivepage.ru/file/?fileid=4563 Тестировал в локальном варианте на простом консольном примере: //----------------------------------------------------------------------------// Function Main() REQUEST LETO RDDSETDEFAULT( "LETO" ) USE "//192.168.0.63:2812/data/test" Browse() USE Return nil //----------------------------------------------------------------------------// Программа работает, хотя и тормозит в Browse на Win98 Консольный manager также нормально работает при нажатии 1-2-3

Andrey: Скачал билд2. Собрал хХарбором letodb.exe и библиотеку. Сделал тестовый пример на Ххарборе, тот что Филатов выше выложил. только пути другие: USE "//127.0.0.1:2812/@/data/test" Запускаю сервер, далее тест получаю: Error LETO/1021 Data type error: -003:21-1001 | Останавливаю все. Беру сборку Филатова, запускаю свой пример на хХарборе, база открывается, броуз показывает. Что делать ??? И по ходу, а где хранится история открытия баз, когда и кем (с какой машины) она была открыта ? И еще у Филатова, сервер нигде не отображается, ни в трее, ни в окне, ни где. Это не есть ХОРОШО !

Pasha: Еще бы сделать, чтобы для seek передавался произвольный ключ. А сейчас, к примеру, ключ, содержащий символ ';', будет обрезан что-то вроде в letoSeek: if( ( bType = leto_ItemType( pKey ) ) != pArea->pTagCurrent->KeyType ) { sprintf( szData,"goto;%d;-3;%s;\r\n", pArea->hTable, (pArea->pTagCurrent)? pArea->pTagCurrent->TagName:"" ); if ( !leto_SendRecv( pArea, szData, 0, 1021 ) ) return FAILURE; } else { USHORT uiTemp; uiKeyLen = letoKeyToStr( pArea, szKey, bType, pKey ); sprintf( szData,"seek;%d;%s;%c%c;", pArea->hTable, (pArea->pTagCurrent)? pArea->pTagCurrent->TagName:"", (bSoftSeek)? 'T':'F', (bFindLast)? 'T':'F' ); uiTemp = strlen(szData); *(USHORT *) (szData + uiTemp) = uiKeyLen; memcpy(szData + uiTemp + 2, szKey, uiKeyLen); memcpy(szData + uiTemp + 2 + uiKeyLen, "\r\n", 2); szData[uiTemp + 4 + uiKeyLen] = '\0'; if ( !leto_SendRecv( pArea, szData, uiTemp + 4 + uiKeyLen, 1021 ) ) return FAILURE; } и в hs_seek IF Empty( nId := Val( GetCmdItem( cCommand,1,@nPos ) ) ) Return "-002" ENDIF IF Empty( cOrder := GetCmdItem( cCommand,nPos+1,@nPos ) ) Return "-002" ENDIF IF Empty( cFlags := GetCmdItem( cCommand,nPos+1,@nPos ) ) Return "-002" ENDIF nKeyLen := Bin2I(Substr( cCommand, nPos+1, 2)) xKey := Substr( cCommand, nPos+3, nKeyLen ) только в этом коде вываливается gpf на *(USHORT *) (szData + uiTemp) = uiKeyLen; не пойму почему

alkresin: Andrey пишет: только пути другие: USE "//127.0.0.1:2812/@/data/test" А что такое /@ ?

alkresin: Pasha пишет: Еще бы сделать, чтобы для seek передавался произвольный ключ. А сейчас, к примеру, ключ, содержащий символ ';', будет обрезан Надо. Ключ ведь теоретически и несимвольный может быть, и с 0 - как ты сам писал раньше. Поэтому тут для передачи надо использовать ту же схему, которая используется для передачи записи. Ты, наверное, уже заметил, что посылка ( в обоих направлениях ) сделана в двух форматах: 1) Простая символьная , признак конца - \r\n 2) Та, что может содержать несимвольную информацию - это когда запись передается с сервера или поля для записи в базу на сервер ( в char полях ведь что угодно может быть ) - в этом случае каждое символьное поле предваряется байтами с его длиной и в начале всей посылки стоит информация о ее длине ( \r\n могут ведь и char поле случайно встретиться ) в таком формате: 1 байт - N количество байтов с информацией о длине посылки (до 10) N байт - длина посылки в специальном формате - функция leto_n2b() ( и leto_b2n() - для обратного преобразования ). Я не использую здесь стандартные функции, потому что формат хранения числа на клиенте и на сервере может быть разным, в зависимости от железа/ОС.

Pasha: Понятно Может, сделать для seek двоичную структуру пакета, когда на сервере процедура обработки seek будет переписана на C ?

alkresin: Да нет, я сегодня сделаю, наверное.

Pasha: Немного поправил использование каталогов при открытии и создании файлов

Pasha: У меня есть такая функция - реструктуризация таблицы (выполняется, естественно, монопольно) Для ее работы необходимы файловые операции rename/delete Добавляем ? И как быть с безопасность данных ?

Петр: Pasha пишет: Добавляем ? И как быть с безопасность данных ? Мое мнение, так же как и в случае со stored proc, сначала нужно разобраться с управлением пользователей. Т.е. перед выполнением любого запроса/действия нужно убедиться, уполномочен ли обьект установивший подключение на выполнение таких действий.

Pasha: Петр пишет: Мое мнение, так же как и в случае со stored proc, сначала нужно разобраться с управлением пользователей. Есть предложения, как это реализовать ?

alkresin: Добавляем. По безопасности - важно то, что эти операции можно сделать только с помощью Leto, т.е.: 1) если это предусмотрел автор программы ( а не рядовой user, не знающий куда деть руки ), а он должен знать, что делает 2) эти операции не опаснее, чем zap, например 3) авторизацию на сервере мы, так или иначе, сделаем - и там в опциях можно будет указать, например, что на удаление/переименование имеет право только админ.

Петр: alkresin пишет: Добавляем. По безопасности - важно то, что эти операции можно сделать только с помощью Leto, т.е.: 1) если это предусмотрел автор программы ( а не рядовой user, не знающий куда деть руки ), а он должен знать, что делает 2) эти операции не опаснее, чем zap, например 3) авторизацию на сервере мы, так или иначе, сделаем - и там в опциях можно будет указать, например, что на удаление/переименование имеет право только админ. То что все операции делаются с помощью серверов - это понятно. По первому пункту - знать то он должен, а на практике.. Если мы считаем операцию ZAP небезопасной - мы можем на сервере ее и не выполнять. Закрыть таблицу, переименовать в какой-то dbf.bak и создать новую с именем и структурой прежней - быстрый бэкап, или более медленный - сохранить каким либо образом все данные и сделать ZAP. Только я вот не понял - в существующем варианте letodb допускает конкурирующих юзерей или нет? По третьему пункту - если этим никто еще не занимается, то я могу внести на рассмотрение свои предложения, правда только после того как решу проблему гриппа..

Pasha: Петр пишет: По третьему пункту - если этим никто еще не занимается Я не занимаюсь

alkresin: Только я вот не понял - в существующем варианте letodb допускает конкурирующих юзерей или нет? Да. По третьему пункту - если этим никто еще не занимается, то я могу внести на рассмотрение свои предложения, Ждем.

Pasha: Мне кажется, надо переделать delete/recall. Сейчас эта команда сразу передается на сервер и немедленно выполняется Надо это делать только при putRec, т.е добавить к этой команде еще один параметр. При нынешней схеме может произойти такая ситуация: dbAppend() // команда на сервер еще не передана dbDelete() // команда на сервер сразу передана и фактически не отработана, поскольку запись еще не добавлена ... dbCommit() // добавлена запись, у которой не установлен флаг deleted()

Pasha: Надо вводить что-то вроде Connection Id. Каждый раз передавать ip-адрес и порт неудобно

Петр: Pasha пишет: Надо вводить что-то вроде Connection Id. Каждый раз передавать ip-адрес и порт неудобно Не знаю, что Вы конкретно имели ввиду, но в принципе согласен что-то вроде CREATE CONNECTION mycon USER "user" PASSWORD "password" IF mycon:ErrorCode() != 0 ? "Извините, сервер недоступен" Return 1 ENDIF USE table1 NEW CONNECTION mycon USE table2 NEW CONNECTION mycon тогда и с авторизацией меньше хлопот буде и обработку ошибок легче будет делать, и проверку "живо" ли соеденение перед операциями с таблицей после длительного простоя или во время длительной операции можно будет организовать..

Pasha: Да, так было бы лучше всего. Тем более параметр nConnection предусмотрен в dbUse/dbCreate Только он должен быть числовой

Петр: Увидя в коде сл.конструкцию и зная об отличии в реализации Adel Harbour и xHarbour сначала заменил j := Ascan( HSTable():aTables,{|o|o==oTable} ) Adel( HSTable():aTables,j ) Asize( HSTable():aTables,Len(HSTable():aTables)-1 ) на j := Ascan( HSTable():aTables,{|o|o==oTable} ) #ifdef __XHARBOUR__ Adel( HSTable():aTables,j, .t. ) #else #include "hbver.h" #if HB_VER_MAJOR >= 1 Hb_Adel( HSTable():aTables,j, .t. ) #else Adel( HSTable():aTables,j ) Asize( HSTable():aTables,Len(HSTable():aTables)-1 ) #endif #endif Потом решил, что это громоздко и по принципу leto_at написал leto_adel, потом опять подумал и решил, что лучше будет использовать leto_ScanAndDel HB_FUNC( LETO_SCANANDDEL ) { PHB_ITEM pArray = hb_param( 1, HB_IT_ARRAY ); PHB_ITEM pValue = hb_param( 2, HB_IT_ANY ); if( pArray && pValue ) { ULONG ulStart = hb_parnl( 3 ); ULONG ulCount = hb_parnl( 4 ); long lPos; lPos = hb_arrayScan( pArray, pValue, ISNUM( 3 ) ? &ulStart : NULL, ISNUM( 4 ) ? &ulCount : NULL, FALSE ); if (lPos > 0 && hb_arrayDel(pArray, lPos) ) { hb_arraySize( pArray, hb_arrayLen( pArray ) - 1 ); } } hb_itemReturn( pArray ); }

alkresin: Мне кажется, надо переделать delete/recall. Сейчас эта команда сразу передается на сервер и немедленно выполняется Надо это делать только при putRec, т.е добавить к этой команде еще один параметр. Да, пожалуй.

alkresin: Что-то вроде CREATE CONNECTION так или иначе надо вводить, чтобы указать логин/пароль, если это требует сервер. А use/create с использованием ID можно ввести опционально, оставив и существующую схему, поскольку она ( существующая ) позволяет оставить код программы без изменений. Я, честно говоря, не вижу проблем с ее использованием. Если пути к файлам хранятся в переменных, инициализируемых в начале программы, как оно по хорошему и должно быть, а не указываются непосредственно в команде USE, то для программиста это изменение пути будет практически незаметно.

alkresin: Петр пишет: Увидя в коде сл.конструкцию и зная об отличии в реализации Adel Harbour и xHarbour А в чем эта разница ? Я не в курсе.

Петр: Дело в том, что xHarbour за счет введения третьего параметра позволяет заменить конструкцию Adel( array, pos ) Asize( array, Len(array)-1 ) на Adel( array, pos, .t. ) третий параметр т.н. <lShrink> Optionally, a logical value can be specified. If .T. (true) is passed, the length of the array is reduced by one element. The default value is .F. (false) leaving the number of elements in <aArray> unchanged Это удобно и выполняется быстрее. В Harbour c недавного времени тоже есть подобная функция - она называется Hb_Adel. Сначала она появилась в xhb.lib, а потом ввиду очевидных преимуществ попала и в core.

Петр: alkresin пишет: Что-то вроде CREATE CONNECTION так или иначе надо вводить, чтобы указать логин/пароль, если это требует сервер. А use/create с использованием ID можно ввести опционально, оставив и существующую схему, поскольку она ( существующая ) позволяет оставить код программы без изменений. Я, честно говоря, не вижу проблем с ее использованием. hSocket := hb_IPConnect( "127.0.0.1", 2812 ) IF hb_IPErrorCode() != 0 ?LETO_FILE("//127.0.0.1:2812/c:/windows/*.*") ENDIF hSocket := NIL Выполнение этого кода меня не порадовало. Сервер обязательно должен требовать авторизацию, другое дело можно позволить анонимный вход с учетной записью по умолчанию и с соответствующими ей правами. Я понимаю, что Вы стремитесь к минимизации переделок существующего кода и это очень хорошо. Но код все равно придется переделывать, добавлять же нужно REQUEST LETO RDDSETDEFAULT( "LETO" ) почему не добавить еще и CREATE CONNECTION cn USER "user" PASSWORD "password" IF cn:ErrorCode() != 0 ? "Извините, сервер недоступен" Return 1 ENDIF OPEN DATABASE base CONNECTION cn IF base:ErrorCode() != 0 ? "Извините, не удалось открыть базу " Return 1 ENDIF USE table1 NEW USE table2 NEW [DATABASE base] .. К тому же, на мой взгяд DataPath в letodb.ini не может быть опциональным, как и IndexPath. И leto_file() должна быть привязана к DataPath/IndexPath Да и сам letodb.ini не может не существовать..

Петр: + added LETO_FERASE(), LETO_FRENAME(), LETO_FERROR() functions Тест успешно пройден hSocket := hb_IPConnect( "127.0.0.1", 2812 ) IF hb_IPErrorCode() != 0 ?LETO_FILE("//127.0.0.1:2812/c:/windows/*.*") ?LETO_FERASE("//127.0.0.1:2812/c:/windows/system.ini") ENDIF hSocket := NIL

Pasha: Петр пишет: почему не добавить еще и CREATE CONNECTION cn USER "user" PASSWORD "password" Этой функции можно было бы передавать еще используемый rdd на сервере: dbfcdx/dbfntx/etc

Pasha: Петр пишет: Тест успешно пройден hSocket := hb_IPConnect( "127.0.0.1", 2812 ) IF hb_IPErrorCode() != 0 ?LETO_FILE("//127.0.0.1:2812/c:/windows/*.*") ?LETO_FERASE("//127.0.0.1:2812/c:/windows/system.ini") ENDIF hSocket := NIL :) что тут еще сказать :)

Pasha: добавил ordCondSet()

Pasha: Какие будут предложения по безопасности ? Давать права на опасные операции на ккаталоги БД или отдельно на таблицы/индексы ?

alkresin: Потом решил, что это громоздко и по принципу leto_at написал leto_adel, потом опять подумал и решил, что лучше будет использовать leto_ScanAndDel Дело хорошее, но надо еще подумать :). Наученный горьким опытом, я заглянул в сырцы xHarbour и обнаружил, что там в hb_arrayScan() уже 6 параметров: ULONG HB_EXPORT hb_arrayScan( PHB_ITEM pArray, PHB_ITEM pValue, ULONG * pulStart, ULONG * pulCount, BOOL bExact, BOOL bAllowChar )

Петр: Pasha пишет: Этой функции можно было бы передавать еще используемый rdd на сервере: dbfcdx/dbfntx/etc Возможно лучше OPEN DATABASE base CONNECTION cn VIA "RDDCDX" Pasha пишет: Какие будут предложения по безопасности ? Давать права на опасные операции на каталоги БД или отдельно на таблицы/индексы ? Давайте определимся, что в нашем случае есть БД - это конкретная таблица или каталог с логически связанными таблицами (+каталог с индексами конечно). Мне кажется, что каталог. Свойства БД мы можем хранить в letodb.ini [SERVER] AllowIP=127.0.0.1;169.128.0.9 AllowAnonymus=TRUE [DATABASE] DBName=base DBPatch=c:\mybase\data DBPatchIndex=c:\mybase\indexes DBCPAGE=RU866 AllowIP=127.0.0.1;169.128.0.9 AllowAnonymus=FALSE При установлении соеденения мы проверяем есть ли у данного пользователя право на подключение к серверу. Сначала проверим на допустимость IP, потом анонимно ли соединение, если анонимно - то позволены ли такие подключения, если именное подключение то проверим допустимость имени и пароля, не подключен ли уже такой пользователь pwd.ini [USER] UserName=master UserPWD=mypwd UserGROUP=ADMINISTRATORS [USER] UserName=user1 UserPWD=myusrpwd UserGROUP=USERS Если все хорошо регистрируем на сервере connection и возвращаем его хендл Потом при выполнении любой операции по хендлу connection определяем пользователя и его права ( в зависимости от того в какую группу мы его включили ) и выполняем или нет - выставляем NO_ACCESS или SERVER_BUSY Это так схема, все технические детали можно будет согласовать после принятия такой схемы, или искать новую

Петр: alkresin пишет: Дело хорошее, но надо еще подумать :) Извините, это я просто забыл об этом, нужно кое-что просто подправить. Схема в xHb уже устоявшаяся. 6-й параметр там уже давно, и связан с тем как xHarbour обрабатывает строку с одного символа. Я сталкивался с этим когда писал wrapper для unrar.dll. Вот этот код if( pArray != NULL ) { if( (PFCode = RARProcessFile(hArcData, (hb_arrayScan(pArray, pValue, NULL, NULL, #ifdef __XHARBOUR__ FALSE, #endif FALSE) > 0) ? Operation : RAR_SKIP, pszDst, NULL)) != 0 ) { OutProcessFileError( PFCode, HeaderData.FileName ); fResult = FALSE; break; } } одинаково хорошо работает и со старой версией xHb (конкретно тестировалось на 0.99.5, 0.99.7 ) и с 1.0. и CVS. Ну и соответственно с Harbour.

alkresin: Петр пишет: К тому же, на мой взгяд DataPath в letodb.ini не может быть опциональным, как и IndexPath. И leto_file() должна быть привязана к DataPath/IndexPath Вопрос о DataPath и о наличии letodb.ini я бы все же предпочел оставить на усмотрение администратора. А вот все файловые функции, включая File(), действительно, надо разрешать только при непустом DataPath, а erase/rename - только для файлов с раширениями .dbf,.fpt,... Вносить какие-то уязвимости на сервер мы не имеем права. Но код все равно придется переделывать, добавлять же нужно REQUEST LETO RDDSETDEFAULT( "LETO" ) Это стандартная вставка для каждого RDD. почему не добавить еще и CREATE CONNECTION cn USER "user" PASSWORD "password" ... Чтобы не вынуждать человека делать то, что ему, может, и не нужно. В значительной части случаев люди переделывают уже существующие программные комплексы под новую платформу, сервер, RDD и в их программах, скорее всего, уже есть какие-то средства авторизации, зачем же заставлять их использовать другие вместо/или дополнительно к своим ? Я представляю себе весь процесс перехода на новый RDD так: сначала человек просто ставит сервер, перекомпилирует свои программы, добавив туда 2 строчки - и все работает так, как оно работало и раньше, но на новой платформе, с использованием преимуществ клиент-серверной схемы. А дальше, при наличии времени и желания он меняет свои программы, добавляя новые возможности.

Петр: alkresin пишет: Вносить какие-то уязвимости на сервер мы не имеем права. Согласен IF LETO_FILE("//127.0.0.1:2812/c:/windows/*.*") dbCreate( "//127.0.0.1:2812/c:/windows/system.ini", aStruct ) ENDIF Кстати, первую уязвимость вашего сервера, показали Вы, Александр: Log=letodb.ini

alkresin: IF LETO_FILE("//127.0.0.1:2812/c:/windows/*.*") dbCreate( "//127.0.0.1:2812/c:/windows/system.ini", aStruct ) ENDIF Так мы же, вроде, договорились, что файловые функции будут работать только при непустом DataPath - а при этом c:\ не прокатит. Кстати, первую уязвимость вашего сервера, показали Вы, Александр: Log=letodb.ini :) ini - файл, при этом, кстати, не пострадает. Впрочем, здесь есть о чем подумать.

Петр: alkresin пишет: Так мы же, вроде, договорились, что файловые функции будут работать только при непустом DataPath - а при этом c:\ не прокатит. Хорошо, вот это тоже не должно работать DataPath=c:/test IF LETO_FILE("//127.0.0.1:2812/../windows/*.*") По сути файловые функции это и dbCreat, INDEX TO, COPY TO и т.п. - еще немного и Вы согласитесь со мной в вопросе о DataPath и наличии letodb.ini

alkresin: DataPath=c:/test IF LETO_FILE("//127.0.0.1:2812/../windows/*.*") Надо будет вставить что-то вроде if At( "..",cPath) != 0 return ERROR endif Но это, кстати, не относится к вопросу об обязательности DataPath :)

alkresin: Давайте определимся, что в нашем случае есть БД - это конкретная таблица или каталог с логически связанными таблицами (+каталог с индексами конечно). А зачем нам вообще вводить такую дополнительную сущность ? Что она дает разработчику, что она для него означает ? Даже если вводить это дело опционально, надо объяснить, что получит программист от его использования. Если это нужно для удобства разграничения прав ( чтоб на каждый файл не писать ), то это можно сделать на уровне серверного модуля ...

Петр: Разработчику БД может и ничего, кроме безопасности, а разработчика сервера (администратора) может от головной боли спасти Ну это почти шутка. Попробую, как смогу, обьяснить идею (по сути позаимствованную у больших РБД). Вот если я знаю, что у меня БД - каталог, я могу создать в этом (?) каталоге таблицу которая содержит всю служебную информацию о содержимом каталога (БД). И мне не надо (серверу) проверять каждый раз есть ли, допустим, в базе данных таблица "разработчики" используя функцию File - достаточно произвести поиск в таблице "мастер" ( да тот самый SELECT name FROM master WHERE obj_name == "разработчики" AND obj_type == TABLE, который в той или иной форме допускают все РБД). Тоже самое относится к блокировкам (Р.Спенс "Кто владеет моей блокировкой" ) К тому же, не знаю как-кто, а я привык обычно размещать таблицы в одной папке, а даже если не так, то кто мешает нам в той же таблице мастер создать запись obj_name obj_type obj_shared obj_attached obj_location ------------------------------------------------------------------------------------------------- продажи table no no %DATAPATH% клиенты table no yes d:\clients\clients.dbf или даже со временем клиенты table no yes //192.168.0.25:2042/clients.dbf Можна организовывать словари таблиц и много чего другого, что на ум придет. Восстанавливать структуру такой таблицы автоматически тоже можно будет, достаточно лищь сохранять информацию о структуре таблиц и индексных файлов, типе RDD. Если позже захочется поиграться с SQL, то тоже будет намного легче, имея такую служебную информацию. Кроме того, раз речь выше шла о stored proc и triggers, то хочу напомнить, что используя Harbour (библиотеку compiler) эти самые процедуры можно будет организовывать без hrb и следовательно обращения к дисковой системе. Менять их удаленно и перекомпилировать на лету (естественно после того как решить все вопросы связанные с авторизацией). Или даже используя hrb (или задекларированные когда-то разработчиками Harbour библиотеки hrb - если их создадут, или создать самим - я думаю это не самое трудное задание) - информацию о них тоже нужно где-то хранить (размещение, контрольную сумму, желательно версию P_CODE) В краткосрочной перспективе. действительно, это может и не дать ничего существенного, но если этим заняться "всерьез и надолго" (хотя бы на год) .. Все - аргументы иссякли, красноречие тоже

alkresin: Все это хорошо, я бы добавил еще в master table возможность сослаться на курсор из какой-нибудь доступной SQL DBMS. Но: 1) Такую master table, также, как и stored proc разных видов, можно организовать, и не пользуясь концепцией database - и тут прилагаем бритву Оккама :). 2) Я все еще не вижу, зачем клиентской программе знать о существовании такого внутреннего разделения данных на сервере на databases и открывать эти databases. Сервер, если databases определены и master tables, управление правами и т.д сделаны на их уровне, может сам определить, к какой database относится открываемая таблица и выполнить соответствующие действия. Я - противник того, чтобы заставлять людей делать то, что им не нужно. Сначала пусть просто запустит letodb.exe, посмотрит, как это работает в деле, не заморачиваясь содержимым ini-файла. Чуть позже, если сочтет это нужным, добавит letodb.ini с DataPath. Потом, может, решит ( а может и нет ), что лучше использовать средства авторизации и определения прав, предлагаемые сервером, и активизирует там эти средства. Может, ему понравится идея master-table, и он активизирует и эту возможность. И так же - с databases, и со всем, что мы здесь придумаем. Но говорить разработчику: вот тебе letodb, чтобы использовать ее, ты должен разбить свои данные на databases, описать все это в ini-файле, создать и заполнить для каждой database master-table и дополнительные файлы системы управления правами, ... Да еще открывать эти databases, без которых ты прекрасно жил до того, в своей программе. Я - против. Кстати, для полной защиты от файловых функций предлагаю добавить в ini-файл опции, разрешающие их - по умолчанию - запрет.

Петр: Отвечать буду не по порядку: alkresin пишет: Я все еще не вижу, зачем клиентской программе знать о существовании такого внутреннего разделения данных на сервере на databases и открывать эти databases. Незачем - если эта клиентская программа не изощренный Manager, позволяющий нам с комфортом админить БД удаленно - добавлять пользователей, менять их роли, менять структуру таблиц, создавать индексы, править stored proc и триггеры или прото смотреть, кто из пользователей сейчас работает, что делает, отключать кто не понравился или всех сразу (в случае плохого настоения или производственной необходимости). Такую master table, также, как и stored proc разных видов, можно организовать.. Можно. Сначала пусть просто запустит letodb.exe, посмотрит, как это работает в деле Согласен. Кстати, здесь несколько возможных пользователей уже заявляли о своей готовности тестировать/использовать такой продукт. Я думаю, что было бы неплохо услышать их мнение, первые впечатления так сказать и, что особенно важно, что они ожидают увидеть в бл.будущем. Но говорить разработчику: Пока никто ничего не говорил. Ini файл придется все равно включать в поставку, пускай и с закомментированными строками, утилиту для проверки это ini файла придется писать (не скармливать же неизвестно, что работающему серверу) - это как в apache (учиться на чужом опыте не должно быть зазорно никому). Создание и заполнение master и прочих служебных таблиц - это дело сервера и (или) admin tools. Про их открытие я уже писал - они сугубо для внутреннего пользования и их использование должно быть по возможности максимально скрыто от конечного пользователя. Тоже относится к управлению правами - по умолчанию для сервера - все пользователи могут быть определены как anonymus. alkresin пишет: Кстати, для полной защиты от файловых функций Не мне Вам говорить, но любая более менее серьезная клипперная программа использует файловые функции - и что каждый раз ходить к серверу - ini править (удаленное да и просто управление правами не реализовано ).

alkresin: Не мне Вам говорить, но любая более менее серьезная клипперная программа использует файловые функции - и что каждый раз ходить к серверу - ini править (удаленное да и просто управление правами не реализовано Зачем каждый раз ? Один раз решить этот вопрос и поставить. Кстати, наверное, надо будет и leto_FOpen(), leto_FRead(), ... сделать. Я не против того, чтобы сделать управление правами, его так или иначе надо будет делать ( опционально! :) ), просто в мои личные рабочие планы это пока не входит. Я только что запостил кое-какие изменения, выработанные на основании нашей дискуссии. Итак: 1) Файловые операции разрешены только при непустом значении DataPath и при EnableFileFunc = 1 в letodb.ini 2) Использование ../ в пути запрещено 3) Создание файлов данных и индексов с нестандартными расширениями разрешено только при наличии EnableAnyExt = 1 в letodb.ini 4) Logfile может быть только с расширением .log :) Да, Петр, как мне вас назвать в Changelog'e ( я там вашу leto_scananddel() добавил ) ?

Петр: Обычно пишу P.Chornyj <myorg63@mail.ru> sourceforge - petr_ch Александр, у меня есть еще несколько мелких замечаний по реализации aSock := hb_ipAccept( Socket ) nOperations ++ IF hb_ipErrorCode() == 0 oSock := HSUser():New( aSock/*[1]*/ ) //oSock:cAddr := aSock[2] //oSock:nPort := aSock[3] Как Вы видите я перенес у себя инициализацию полей cAddr, nPort в метод New - мне кажется так оно быстрее вертеться будет, исходя из мого понимания реализации ООП в Harbour, возможно я и ошибаюсь. Сл., возможно Request ; ABS,; ALLTRIM,; надо вынести в отдельный ch по типу hbexternal.ch также я заменил IF cItem == "skip" cReply := hs_skip( oUser,Substr(cCommand,nPos1+1) ) ELSEIF cItem == "seek" cReply := hs_seek( oUser,Substr(cCommand,nPos1+1) ) на nItem := AScan( aCommand, cItem ) SWITCH nItem CASE 1 cReply := hs_skip( oUser,Substr(cCommand,nPos1+1) ) EXIT никакого существенного выиграша это не дает, наверное из-за AScan, но xHarbour не позволяет использовать CASE "skip" , Я понимаю, что возможно все это когда нибудь будет переписано на C (или не будет ), но все же хочу завтра переписать GetCmdItem и потестировать. Сл. очень часто используется Ltrim(Str( Для таких случаев xHb в Str имеет четвертый параметр <lTrim> - This parameter defaults to .F. (false). When .T. (true) is passed, the returned string has no leading spaces. И может еще что-то менял у себя, вспомню напишу.

alkresin: sourceforge - petr_ch Это запрос на добавление в список developer'ов :) ? Если да, то добавлю, конечно. Я понимаю, что возможно все это когда нибудь будет переписано на C (или не будет Обязательно будет, и не только это.

Петр: alkresin пишет: Это запрос на добавление в список developer'ов :) Да, пока управление правами никто не застолбил (опционально, конечно)

alkresin: Добавил.

alkresin: Петр, вы забыли в Changelog запись занести и, желательно, на https://sourceforge.net/forum/forum.php?forum_id=779825

Петр: Спасибо, внес. errorsys на С переводить будем?

alkresin: errorsys на С переводить будем? А зачем ? Выигрыша в скорости это не даст.

Петр: Я собственно о WrLog - бы иметь общую функцию и для PRG и для C

alkresin: Может, и стоит. Пока необходимости не возникало, поэтому и не думал на эту тему.

alkresin: Перевел значительные куски сервера, включая ParseCommand, на С. Теперь можно смотреть в сторону дополнительных процессов и потоков.

Andrey: Полез пробовать утилиту и получил ошибку: Error BASE/1004 No exported method: SEND Called from SEND(0) Called from USERSINFO(212) Called from (b)MAIN(88) Called from ONCOMMAND(286) Called from (b)(_INITSTATICS00003)(0) Called from HCONTROL:ONEVENT(148) Called from HPANEL:ONEVENT(93) Called from HWG_ACTIVATEMAINWINDOW(0) Called from HMAINWINDOW:ACTIVATE(231) Called from MAIN(100) HwGUI 2.16 Harbour devel build 1.1-1 Intl. Date:02/18/08 Time:13:26:03 Потом догадался, что не ввел IP-adres & Port. Надо бы сделать для "чайников" обработку и надпись для ввода.

Andrey: Что-то не получается у меня открыть FOX базу на сервере. Добавил VIA "RDDCDX" - ругается USE "//192.168.220.3:2812/FOND/DAT/spiski" SHARED NEW VIA "RDDCDX" что: Subsystem Call ....: DBCMD System Code .......: 1015 Default Status ....: .F. Description .......: Неверный аргумент Operation .........: DBUSEAREA Arguments .........: Involved File .....: Dos Error Code ....: 0 Если убрать VIA то пишет: Open error (21-1001): E:\WORK_UCHET/FOND/DAT/spiski Другой dbf файл без МЕМО открывает нормально.

lista: >А NTX-ы поддерживает ? А программный код дорабатывать нужно и насколько ? >А то у меня есть задачка на Clipper-е, которая реально работает 10 лет в сети, и нагрузка приличная. Можно было >бы потестировать, да и быстродействие сравнить. А на Линух перетащить под Clip. У меня работает на Ура!

alkresin: Что-то не получается у меня открыть FOX базу на сервере. А просто Харбором c DBFCDX она открывается ?

Andrey: alkresin пишет: А просто Харбором c DBFCDX она открывается ? Конечно открывается, я просто подключил рабочую базу на сервере и решил с ней параллельно проэксперементировать. И затык.....

alkresin: Ну пришлите мне ее на email, только очистите сначала zap'ом

alkresin: lista пишет: А на Линух перетащить под Clip. Можно и так, в терминале с stelnet. Кстати, таким же образом можно и под Харбор.

abakkav: А что делать с собственными функциями в индексном выражении? Эта проблема уже всплывала?

alkresin: А что делать с собственными функциями в индексном выражении? Эта проблема уже всплывала? Я вижу здесь 2 варианта: 1) Избавляться от них - как при использовании ADS 2) Собрать сервер вместе с этими функциями

abakkav: Мысль понятна. Интересно, а как с этим борется Польский медиатор? Он вообще не индексирует на сервере или передает клиенту, если ключ нестандартный?

Andrey: А можно привести пример открытия БД с мемо полем FPT ? Может быть я синтакис неправильно делаю ?

Andrey: Петр пишет: Кстати, здесь несколько возможных пользователей уже заявляли о своей готовности тестировать/использовать такой продукт. Я думаю, что было бы неплохо услышать их мнение, первые впечатления так сказать и, что особенно важно, что они ожидают увидеть в бл.будущем. Какие нафиг впечатления ..... Вы сами по себе о чем-то обсуждаете, а простой пример как правильно работать с базой, даже и не подумали выложить. Не все такие продвинутые в разработке. Я например просто использую БД для своих задач. А как это работает подглядывая на исходный код реализованный вами .... догадываться сложно. Давайте коротко: 1) какой RDD доступен сейчас. (у меня не открывается база с мемо FPT) 2) пример доступности сервера и открытия, создания БД (простой и продвинутый) 3) пример индексов к этим базам 4) отдельные файлы для сборки сервера leto db со своими функциями 5) файловые операции на сервере Для начала пока хватит . Да еще: выход из сервера при незакрытой задачи не должен быть !!! Руки даже у админа бывают кривые (смотря какой попадется), а отвечать за утерянные данные придется программисту (даже в лог ничего не пишется ) !

alkresin: А можно привести пример открытия БД с мемо полем FPT ? Может быть я синтакис неправильно делаю ? Да обычный синтаксис, ничем не отличается от других: USE "//..../path/test.dbf"

alkresin: Вы сами по себе о чем-то обсуждаете, а простой пример как правильно работать с базой, даже и не подумали выложить. Вот такой пример устроит ? Function Main Local cTable, arr Local i, n1, n2, nSec, s REQUEST LETO RDDSETDEFAULT( "LETO" ) cTable := "//199.10.11.5:2812/test1.dbf" arr := { { "FirstName", "C", 20, 0 }, ; { "LastName", "C", 20, 0 }, ; { "Age", "N", 3, 0 }, ; { "Date", "D", 8, 0 }, ; { "Rate", "N", 6, 2 }, ; { "Student", "L", 1, 0 } } dbCreate( cTable, arr ) use (cTable) new ? "Test 1 " nSec := Seconds() for i := 1 to 200000 append blank n1 := hb_RandomInt( 80 ) n2 := hb_RandomInt( 50 ) replace Age with n1, ; Date with Date() - 365*n2 + n1, ; Rate with 56.5 - n1/2 replace FirstName with "A"+Chr(64+n2)+Padl(i,10,'0'), ; LastName with "B"+Chr(70+n2)+Padl(i,12,'0'), ; Student with ( (field->Age % 2) == 1 ) unlock next ?? "Finished in "+Ltrim(Str(Seconds()-nSec))+" seconds" ? "Test 2 " nSec := Seconds() index on Age tag Age ?? "Finished in "+Ltrim(Str(Seconds()-nSec))+" seconds" use use (cTable) new go top ? "Test 3 " nSec := Seconds() do while !Eof() s := FirstName skip enddo ?? "Finished in "+Ltrim(Str(Seconds()-nSec))+" seconds" use use (cTable) new set order to 1 go top ? "Test 4 " nSec := Seconds() do while !Eof() s := FirstName skip enddo ?? "Finished in "+Ltrim(Str(Seconds()-nSec))+" seconds" use ? Return Nil 1) какой RDD доступен сейчас. (у меня не открывается база с мемо FPT) RDD один - LETO, на сервере поднят DBFCDX. У меня файлы с мемо fpt открываются, поэтому я и просил вас прислать свой, может в нем что необычное - только не весь, конечно, оставьте в нем пару записей. 2) пример доступности сервера и открытия, создания БД (простой и продвинутый) 3) пример индексов к этим базам См. пример выше. 4) отдельные файлы для сборки сервера leto db со своими функциями Не понял, что имеете ввиду. 5) файловые операции на сервере Это к Pasha, я их сам еще не пробовал.

alkresin: abakkav пишет: Интересно, а как с этим борется Польский медиатор? Он вообще не индексирует на сервере или передает клиенту, если ключ нестандартный? Понятия не имею, я его не пробовал. А что, он это умеет ? В принципе, здесь можно это, наверное, реализовать - через custom индекс, вычисляя ключи на стороне клиента.

abakkav: Не знаю как, но медиатор допускает собственные ф-ции в индексе и не требует пересобирать серверную часть. А реализовать "через custom индекс" или формируя запрос на клиента в случае нестандартного индекса было бы здорово.

Andrey: alkresin пишет: 4) отдельные файлы для сборки сервера leto db со своими функциями Не понял, что имеете ввиду. Про то, что задавал вопрос: abakkav пишет: собственные ф-ции в индексе

Pasha: Опять мистика какая-то Собрал letodb под xHarbour При попытке открытия 22-й по порядку (в разных программах!) таблицы сервер вываливается по gpf на строке IF ( oTable := HSTable():Find( cName ) ) == Nil в hs_opentable, причем до вызова метода Find дело не доходит, управление в HSTable():Find не передается 2 недели назад этого не было

alkresin: Догадываюсь, в чем там дело. Попробуйте поменять в line 665: pUStru->uiAreasAlloc = 20; 20 на что-нибудь побольше - 40, например.

Pasha: сейчас попробую Простой тест: Local cPath := '//127.0.0.1:2812/' use (cPath+'table1') new use (cPath+'table2') new ... use (cPath+'table25') new стабильно приводит к gpf на сервере на 25-м use при сборке под xHarbour При сборке под Harbour gpf нет Но при попытке открытия (use) несуществующей таблицы gpf на сервере происходит как для xHarbour, так и для Harbour По поводу udf-функций. Пересборка сервера с нужными функциями для некоторых может вызвать затруднения. Да и добавление новых функций приведет к необходимости пересобрать сервер, что нежелательно Может быть, сделать dll для udf-функций, которую бы сервер загружал, и предоставить программисту добавлять свои функции в эту dll и пересобирать ее ? Хотя, как-то надо указывать codepages, которые должен использовать сервер, то есть без пересборки не обойтись

Pasha: Да, теперь все работает

Pasha: Смотрю вопросы в Open discussion Наверное, надо заменить: IF !oApp:lAnyExt .AND. !Empty( cBagName ) .AND. Len( cTemp := GetExten( cBagName ) < 3 ) .AND. !( cTemp $ "cdx;idx;ntx" ) на IF !oApp:lAnyExt .AND. !Empty( cBagName ) .AND. Len( cTemp := GetExten( cBagName ) ) < 3 .AND. !( cTemp $ "cdx;idx;ntx" ) ?

Andrey: Когда можно будет приступить к тестированию СЕРВЕРА БД под свои рабочие базы ? Я писал об БОЛЬШОЙ проблеме открытия баз с большим количеством полей !!! Если надо образцы баз на которых не работает сервер leto DB , могу выслать.

alkresin: Pasha пишет: Наверное, надо заменить: IF !oApp:lAnyExt .AND. !Empty( cBagName ) .AND. Len( cTemp := GetExten( cBagName ) < 3 ) .AND. !( cTemp $ "cdx;idx;ntx" ) Точно. Сейчас заменю.

alkresin: Andrey пишет: Я писал об БОЛЬШОЙ проблеме открытия баз с большим количеством полей !!! Я все исправил, теперь должно работать нормально. Думаю выложить build3 сегодня-завтра.

spair2k: в посте говорилось о том, что главная идея этого проекта в легкости переноса существующего кода на другую платформу "добавив 3 строчки кода". попробовал, начал с создания индексов, получилось, но заметил одну вещь - не создаются индексы в которых есть FOR, т.е. в самом индексе TAG прописан, но он пустой. это только у меня проблема?

Pasha: spair2k пишет: но заметил одну вещь - не создаются индексы в которых есть FOR, т.е. в самом индексе TAG прописан, но он пустой. Это на build2 или на свежих сырцах ? Пару недель назад я добавлял OrdCondSet(), должно работать Команду, которой создается индекс, в студию

alkresin: Выложил build3

gfilatov: alkresin пишет: Выложил build3 Выложил готовую к использованию полную сборку LetoDB build 0.3 по адресу: http://minigui.mylivepage.ru/file/16/4742_letodb-bin-w32-bcc-5-5.zip.zip

Pasha: Александр, все-таки более 20-ти таблиц не открываются, на сервере происходит gpf Надо увеличить в letofunc.c параметр pUStru->uiAreasAlloc ? И еще возник глючек. После dbAppend() Field->F1 := value ... dbCommit() dbUnlock() на последней команде клиент зависает, по-видимому безуспешно ждет ответ от сервера

alkresin: Александр, все-таки более 20-ти таблиц не открываются, на сервере происходит gpf Надо увеличить в letofunc.c параметр pUStru->uiAreasAlloc ? Это просто отодвинет барьер после которого происходит gpf. Надо разобраться, в чем дело.

Pasha: Смотрю, как бы получше сделать relations Надо и на клиенте, и на сервере хранить установленные relations в каждой РО Затем, на сервере в leto_rec их отрабатывать, и передавать на клиент данные не только текущей РО, но и всех РО, указанных в relations На клиенте их принимать, и соответственно отрабатывать в leto_ParseRec Только при этом надо учесть отложенные commit в связанных РО: проверять не только pArea->uiUpdated, но и изменения в связанных РО Такая схема подойдет ?

alkresin: Александр, все-таки более 20-ти таблиц не открываются, на сервере происходит gpf Теперь окончательно исправил.

Pasha: Теперь БД открывается без проблем

alkresin: Смотрю, как бы получше сделать relations Надо и на клиенте, и на сервере хранить установленные relations в каждой РО Затем, на сервере в leto_rec их отрабатывать, и передавать на клиент данные не только текущей РО, но и всех РО, указанных в relations... Чем больше думаю об этом, тем труднее представляю, как это можно сделать корректным путем. RDD методы имеют дело с одной текущей workarea, которая передается им в качестве параметра, а при таком подходе каждый метод, связанный с перемещением по базе, будет получать и должен обрабатывать данные для разных workareas - сделать-то можно, но это нарушает всю логику работы RDD. Не думаю, что это хорошо.

alkresin: Создал developers mail list, подписка на https://lists.sourceforge.net/lists/listinfo/letodb-developers

Pasha: Буду делать аккуратно Постараюсь, чтобы методы workarea не выходили за пределы своих полномочий Все равно, эффективнее было бы получать посылку от сервера о состоянии всех связанных РО одним пакетом. Да по-другому, наверное, нельзя

alkresin: Выложил build4, т.к. были важные исправления

gfilatov: alkresin пишет: Выложил build4 Выложил готовую к использованию полную сборку LetoDB build 0.4 по адресу: http://minigui.mylivepage.ru/file/16/4777_letodb-bin-w32-bcc-5-5.zip.zip

Pasha: После перемещения записи в основной РО можно сохранять новое состояние дочерних РО в области данных LETOAREA основной РО Затем, когда letoSyncChildren вызовет letoChildSync дочерних РО, этот метод должен будет отработать изменившеся состояние своей РО, взяв его из области данных master-РО Правда, будет проблема, если у дочерних РО тоже есть свои relations. Но обработку таких каскадных relations можно тоже возложить на сервер при первоначальной операции перемещения. Возникает вопрос: а как сбросить на сервер текущие записи дочерних РО перед перемещением записи в основной РО ? Делать это в letoChildSync уже поздно, поскольку сервер уже выполнил операцию перемещения записи

Andrey: Тестирую сервер, столкнулся с неудобствами, как писал ранее : 2) пример доступности сервера ??? Как проверить "запущен" ли leto db на сервере ??? alkresin пишет: цитата: 5) файловые операции на сервере Это к Pasha, я их сам еще не пробовал. Паша ! Дай пожалуйста эти функции !!! Самый НЕПРИЯТНЫЙ МОМЕНТ, если на сервере сняли letoDb, то "труба" - у пользователей база летит. Нужно наверно повесить сообщение типа ALERT("Есть открытые базы ! Не все клиентские места закрыты!") Это хоть как то защитит от "кривых рук" админов (не у всех есть нормальные) и воплей начальства, ему сложно доказать, что ты не верблюд и не по твоей вине это произошло !!! И еще до кучи: Как править letodb.ini ? Может у меня доступа нет к серверу, а его нужно исправить !!! И как потом перезапустить сервер letodb ? У меня есть на работе Дельфовая задача по Субсидиям. Там решается такая вещь просто. Если все пользователи вышли из клиентских мест, то СЕРВЕРНАЯ ЗАДАЧА завершается. Как кто-нибудь запускает клиенское место, так СЕРВЕРНАЯ ЗАДАЧА сама стартует и в трей !

Pasha: Andrey пишет: Паша ! Дай пожалуйста эти функции !!! Leto_File(<cFile>) Leto_FErase(<cFile>) Leto_FRename(<cFile>, <cNewName>) cFile имеет такую же структуру, какая используется для use: //ip_address:port/data_path/file_name Чтобы разрешить их использование, надо в letidb.ini на сервере указать EnableFileFunc = 1

alkresin: Возникает вопрос: а как сбросить на сервер текущие записи дочерних РО перед перемещением записи в основной РО ? Делать это в letoChildSync уже поздно, поскольку сервер уже выполнил операцию перемещения записи Вопросов немало, потому что нарушается стандартная схема. Обычно перемещение в дочерних областях происходит не сразу при перемещении в родительской, а только при попытке чтения/записи в эту конкретную дочернюю область.

alkresin: 2) пример доступности сервера ??? Как проверить "запущен" ли leto db на сервере ??? С помощью manager'а. Самый НЕПРИЯТНЫЙ МОМЕНТ, если на сервере сняли letoDb, то "труба" - у пользователей база летит. База от этого не полетит, т.к. при завершении работы сервер все базы аккуратно закрывает. А вот предупреждение выдать стоит. Подумаем, как это лучше сделать. И еще до кучи: Как править letodb.ini ? Может у меня доступа нет к серверу, а его нужно исправить !!! Так в том-то и фишка, что без ведома администратора сервера его нельзя править ( если только он не поместит его в расшаренной папке - но я бы не советовал :) ). Иначе к чему все разговоры о безопасности ??? И как потом перезапустить сервер letodb ? letodb stop letodb Опять-таки, администратор или доверенный человек должен делать. У меня есть на работе Дельфовая задача по Субсидиям. Там решается такая вещь просто. Если все пользователи вышли из клиентских мест, то СЕРВЕРНАЯ ЗАДАЧА завершается. Как кто-нибудь запускает клиенское место, так СЕРВЕРНАЯ ЗАДАЧА сама стартует и в трей ! Так, наверное, там на сервере еще один процесс невидимый ( daemon, как наш сервер, запущен ), он это и делает, управляет "СЕРВЕРНОЙ ЗАДАЧЕЙ", которая общается с клиентами. В чем преимущество-то ?

Pasha: По-видимому, на сервере надо предусмотреть возможность работы с несколькими БД. Наверное, перечислять их в DataPath через точку с запятой Или делать по другому. Ввести алиасы БД и для них указывать каталоги Как лучше ?

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

spair2k: Pasha пишет: Это на build2 или на свежих сырцах ? Пару недель назад я добавлял OrdCondSet(), должно работать Уже успел проверит на build4 - результат тот же Команду, которой создается индекс, в студию Задача: Есть табличка с ценами услуг,цены с историей, нужны свежие Код: USE (server+'price') NEW INDEX ON date TAG tmp UNIQUE DESCENDING //сортируем в обратном порядке GO TOP // нахожу самую свежую дату изменения cDT := chr(39)+dtos(price->date)+chr(39) // создаю подстановку для FOR INDEX ON usluga TAG usluga FOR dtos(date)='20080201' //&cDT //(два варианта - работают одинаково) создаются индексы, TAG с условием прописан, но в индексе все записи... кстати, сейчас проверил - tmp создан тоже без обратного порядка, без сортировки

Andrey: alkresin пишет: цитата: 2) пример доступности сервера ??? Как проверить "запущен" ли leto db на сервере ??? С помощью manager'а. И что, каждого юзера научить пользоваться этим manager'ом ? Нужно до открытия БД в программе сделать проверку. Здесь был кусок кода, но он у меня не работает ! Петр пишет: CREATE CONNECTION cn USER "user" PASSWORD "password" IF cn:ErrorCode() != 0 ? "Извините, сервер недоступен" Return 1 ENDIF Или типа такого: hSocket := hb_IPConnect( "127.0.0.1", 2812 ) IF hb_IPErrorCode() = 0 ? "Извините, сервер недоступен" ENDIF hSocket := NIL

Pasha: По поводу FOR - в моих программах индекс создается с этим условием. Проверял как только сделал Возможно, причина в том, что у тебя создаются 2 разных индексных файла для одной таблицы. Вообще-то при использовании dbfcdx принято использовать один индексный файл, я даже не знаю, как rdd на такое отреагирует. Изначально код был для dbfntx ? Descending. Во всяком случае команда создания индекса на сервер послупает с опцией Descending Попробуй указать отдельно OrdDescend(,, .t.) // включить обратную сортировку OrdDescend(,, .f.) // выключить

Pasha: Andrey пишет: Здесь был кусок кода, но он у меня не работает ! Это не рабочий код, а только предложение Петра по организации БД

alkresin: Или типа такого: hSocket := hb_IPConnect( "127.0.0.1", 2812 ) IF hb_IPErrorCode() = 0 ? "Извините, сервер недоступен" ENDIF А... Ну это дело пары минут. Сделаем. Просто, на мой взгляд, пока нет системы идентификации ( логин/пароль ), это - излишество. Сервер ДОЛЖЕН работать всегда. Если не работает, клиентская программа просто вылетает с ошибкой открытия файла и пользователь идет высказывать законное возмущение соответствующим службам.

Andrey: alkresin пишет: это - излишество. Сервер ДОЛЖЕН работать всегда. Если не работает, клиентская программа просто вылетает с ошибкой открытия файла и пользователь идет высказывать законное возмущение соответствующим службам. А если программы крутяться в других городах (у меня так) и там программист приходящее лицо по вызову, СЕРВЕР не выделенный, а обычный комп для работы... Ну и что они делать будут ??? Да они по телефону задолбают меня ! И сколько будет высказано "всего хорошего" в адрес программиста, написавшего программу.... Знаете, не хочется терять клиентов из-за мелочей !!! Нужна проверка и внятное сообщение для пользователя, чтоб не дергали меня по пустякам из-за своего раздол....................

Pasha: Начал делать VarField aka "V", HB_FT_ANY, и столкнулся с необходимостью в ParseRec уже формировать готовый ITEM, поскольку нет необходимости повторять на клиенте разбор этого поля Может быть, где-то записывать этот Item и затем в GetValue его брать ? Клиенту лучше абстрагироваться от низкоуровневого формата данных сервера Написал такой код в leto_rec, и вижу, что корректно обработать такие данные в ParseRec не получается, поскольку полученные данные могут вылезти за пределы отведенной области pRecord для такого поля case HB_FT_ANY: SELF_GETVALUE( (AREAP)pArea, ui+1, pItem ); if( pField->uiLen == 3 || HB_IS_DATE( pItem ) ) { *pData++ = 'D'; hb_itemGetDS( pItem, (char *) pData); pData += 8; } else if( pField->uiLen == 4 || HB_IS_NUMERIC( pItem ) ) { char * szString = hb_itemStr( pItem, NULL, NULL ); char * szTemp; *pData++ = 'N'; if( szString ) { szTemp = szString; while( HB_ISSPACE( *szTemp ) ) szTemp ++; uiLen = strlen( szTemp ); memcpy( pData, szTemp, uiLen ); pData += uiLen; hb_xfree( szString ); } *pData++ = '\0'; } else if( HB_IS_STRING( pItem ) ) { uiLen = hb_itemGetCLen( pItem ); if( uiLen <= pField->uiLen ) { char * szString = hb_itemGetC( pItem ); *pData++ = 'C'; *pData++ = (BYTE) uiLen & 0xFF; *pData++ = (BYTE) (uiLen >> 8) & 0xFF; memcpy( pData, szString, uiLen ); } else { *pData++ = '!'; } } else { *pData++ = 'U'; } break; Еще предложение: передавать HB_FT_DATE в 3-х или 4-х байтовом формате, а HB_IT_DATETIME (дата и время) в 8-ми байтовом Есть еще двоичные Numeric-поля размером 2 и 4 байта

alkresin: spair2k пишет: создаются индексы, TAG с условием прописан, но в индексе все записи... кстати, сейчас проверил - tmp создан тоже без обратного порядка, без сортировки Да, были там ошибки, только что исправил - и с for и с descending.

alkresin: Начал делать VarField aka "V", HB_FT_ANY А что такое HB_FT_ANY ? Это есть в DBFCDX ? Еще предложение: передавать HB_FT_DATE в 3-х или 4-х байтовом формате Я сначала так и сделал, а потом из-за того, что функции, которые я использовал при этом, оказались не во всех версиях Harbour/xHarbour, стал передавать Date без перекодировки. Не было времени копаться в посках совместимого решения, тем более, что еще неизвестно, восполнит ли экономия на 4-х байтах потери времени на кодировку/раскодировку ... HB_IT_DATETIME (дата и время) в 8-ми байтовом Есть еще двоичные Numeric-поля размером 2 и 4 байта И это все в DBFCDX есть ?

Pasha: alkresin пишет: А что такое HB_FT_ANY ? Это есть в DBFCDX ? Это поля из SIX. Если размер поля 3 байта, тогда значение - дата в Julian формате, если 4 - значение LONG, если больше - любой тип данных Если длина строки превышает длину поля, то хвост строки записывается как memo-поле тем более, что еще неизвестно, восполнит ли экономия на 4-х байтах потери времени на кодировку/раскодировку ... Думаю, что нет. Эта перекодировка все равно выполняется Я уже сделал поддержку полей D, 3 и D, 4 (дата в Julian-формате), сейчас проверяю В dbfcdx есть числовые поля с сигнатурой '2' и '4' - соответственно 2-х и 4-х байтовое целое Типов полей там сейчас довольно много

Pasha: Кстати, в server.prg пропало изменение Miguel: cIndex += OrdBagName(i) + ";" + OrdName(i) + ";" + cName + ";" + OrdFor(i) + ";" + dbOrderInfo(DBOI_KEYTYPE,, i) + ";" + LTrim(Str(dbOrderInfo(DBOI_KEYSIZE,, i))) + ";" Это случайно ? Надо восстановить ?

alkresin: Кстати, в server.prg пропало изменение Miguel: Это случайно ? Да, случайно.

Pasha: По поводу memo-полей возникла такая мысль Значание memo-поля передается на сервер во время PutValue, а остальных полей - во время выполнения Commit, что не очень хорошо Может быть передавать значения memo-полей отдельными пакетами вместе с командой update ? А по putvaluе сохранять где-нибудь это значение на клиенте, без передачи на сервер ?

Andrey: Портирую свою легкую задачу на LetoDB и столкнулся с такой проблемой: Шаблоны печати храню на сервере в папке FORM, это могут быть просто мои текстовые файлы *.ini *.frm, вордовские файлы *.doc и *.xls и отчеты FastReporta. Вопрос такой - нужна функция копирования выбранного файла с сервера на клиентское место (и обратно, если юзер поменял или изменил шаблон !!!). Хотелось бы иметь средства запрета изменения шаблонов, если пользователю нет доступа к такой операции.

alkresin: Может быть передавать значения memo-полей отдельными пакетами вместе с командой update ? А по putvaluе сохранять где-нибудь это значение на клиенте, без передачи на сервер ? Пожалуй, да. Можно добавить в LETOAREA массив BYTE * для хранения memo-полей. Количество элементов массива - по количеству полей, признак update - ненулевое значение элемента.

alkresin: Шаблоны печати храню на сервере в папке FORM, это могут быть просто мои текстовые файлы *.ini *.frm, вордовские файлы *.doc и *.xls и отчеты FastReporta. Вообще говоря, манипуляция текстовыми, а тем более must_die файлами :) не входит в компетенцию dbfcdx сервера. Файлы эти можно, как и сейчас, хранить в расшаренной папке и копировать их средствами ОС. "Средства запрета изменения шаблонов" - просто установка прав на эти файлы. Кстати, добавил функцию leto_Connect( cPath ), возвращает -1 в случае неудачи.

Andrey: alkresin пишет: Файлы эти можно, как и сейчас, хранить в расшаренной папке и копировать их средствами ОС. Неэффективно тогда получается. Разговор шел о сервере который возьмет на себя защиту данных и чтоб для разработчика это было удобно. Попробуйте распространять сетевую программу по многим городам и чтоб была простая установка и обновление. Очень несовместимые вещи. Посмотрите на БЭСТ4+, БЭСТ5 - там тоже до ума не доведено. А 1С обновлять - целая религия, в БЭСТ5 даже лучше. Так как распространяю свою сетевую программу по многим городам, набрался опыта и столкнулся с трудностями: по установке сети, а затем обновления этих программ. Админы в городах как хотят так и ставят мою программу. Заставит их "расшарить" папки - это просто ..... уму не постижимо, нет слов. Юзера продвинутые (руки им поотрывать) додумываются ставить с дистрибутивов предназначенных для других городов. Базы за 2-3 года стирают за момент и еще удивленно говорят: я же думала там программа новее и решила обновить. И руководителю фиг объяснишь что таких людей нельзя допускать к компьютеру, он к тебе с претензией - а что разве нельзя было предусмотреть защиту. ЗНАЧИТ ЗАЩИТУ от ДУРАКА (админа, пользователя) нужно ставить СРАЗУ !!! И даже бэкап не поможет. Ваш сервер очень прост в сетевой настройке !!! Это большой плюс ! Если бы еще он поддерживал эти 2 функции, то для программиста было бы проще работать с формами. Это же просто считать файл на сервере в память и передать клиенту. Туда и обрато ..... Не будем же эти формы запихивать в МЕМО-поля ? alkresin пишет: Кстати, добавил функцию leto_Connect( cPath ), возвращает -1 в случае неудачи. Спасибо !

VivaVO: Andrey пишет: Неэффективно тогда получается. Разговор шел о сервере который возьмет на себя защиту данных и чтоб для разработчика это было удобно. Попробуйте распространять сетевую программу по многим городам и чтоб была простая установка и обновление. Очень несовместимые вещи. Посмотрите на БЭСТ4+, БЭСТ5 - там тоже до ума не доведено. А 1С обновлять - целая религия, в БЭСТ5 даже лучше. Так как распространяю свою сетевую программу по многим городам, набрался опыта и столкнулся с трудностями: по установке сети, а затем обновления этих программ. Админы в городах как хотят так и ставят мою программу. Заставит их "расшарить" папки - это просто ..... уму не постижимо, нет слов. Юзера продвинутые (руки им поотрывать) додумываются ставить с дистрибутивов предназначенных для других городов. Базы за 2-3 года стирают за момент и еще удивленно говорят: я же думала там программа новее и решила обновить. И руководителю фиг объяснишь что таких людей нельзя допускать к компьютеру, он к тебе с претензией - а что разве нельзя было предусмотреть защиту. Что-то типа «Золотая рыбка». А конец знаешь?

alkresin: Это же просто считать файл на сервере в память и передать клиенту. Туда и обрато ..... Не будем же эти формы запихивать в МЕМО-поля ? А почему бы и нет ? С точки зрения безопасности и независимости от окружения очень даже неплохо. Но две такие файловые функции, чтоб считывала файл целиком и целиком записывала я планирую добавить.

Pasha: Взял на заметку, поскольку сейчас занимаюсь relations. Лучше всего пусть это будет массив PHB_ITEM, поскольку там могут быть не только null-terminated strings, да и этим я решу оставшуюся проблемку с VarField. Еще одно рацпредложение. А что, если pArea->pTagCurrent->TagName передавать не с каждой командой навигации по таблице, а по OrdSetFocus, хранить cOrder на сервере в oArea и использовать при необходимости ?

alkresin: А что, если pArea->pTagCurrent->TagName передавать не с каждой командой навигации по таблице, а по OrdSetFocus, хранить cOrder на сервере в oArea и использовать при необходимости ? Черт его знает ... Не уверен, что это даст выигрыш в производительности. С одной стороны, уменьшение длины пакета на несколько байт, с другой - лишний пакет время от времени. Надо тестировать.

alkresin: Добавил поддержку MT. Теперь на сервере крутятся 2 потока. Один принимает соединения, опрашивает сокеты и читает с них данные, а также отвечает на те запросы, которые не требуют обращения к RDD, он работает только на С уровне, не трогает Харборовский стек и VM. Второй обрабатывает запросы, требующие обращения к RDD, т.е. основную массу запросов. Это позволяет серверу, вне зависимости от загруженности работой с dbf, своевременно подключать и отключать пользователей, отвечать на management запросы ( надо будет этому первому потоку еще и файловые функции отдать ).

Andrey: Классно !!! А когда можно будет попробывать ?

alkresin: А когда можно будет попробывать ? Пора CVS осваивать :). Это очень просто - скачать клиент, настроить - и у вас всегда, когда надо, свежайшие исходники.

alkresin: Вот такой батник для консольного CVS: @echo off SET CVSROOT=:pserver:anonymous@letodb.cvs.sourceforge.net:/cvsroot/letodb SET HOME=c:\cvs c:\cvs\cvs login c:\cvs\cvs checkout -P letodb

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

Pasha: Замечательно А я еще неделю назад код написал, да все отладить не мог :(

alkresin: Паша, я тут подумал - стоит, наверное, передавать на сервер не имя тэга, а порядковый номер, ведь в структурах на клиенте и в LETOTAG на сервере порядок следования тот же. Дело в том, что делать так, как в leto_Scope() - определять номер тэга и по нему брать элемент в LETOTAG - неправильно. В общем случае ( особенно это будет часто для ntx ) количество и порядок следования тэгов для общей таблицы ( определяемые по orderinfo ) и для конкретной workarea могут отличаться. Я, наверное, это сделаю ближе к вечеру, если нет возражений.

Pasha: Лучше конечно делать все для общего случая, расчитывая сразу и на ntx Может в LETOTAG добавить имя тэга и по нему выполнять поиск ?

alkresin: Сначала я так и хотел сделать, но потом подумал: сколько дублирования будет - по числу пользователей одного индекса, ну и затраты на сравнение строк/поиск. А тут сразу номер готовый придет.

Pasha: Хорошо, пусть будет номер

alkresin: Не все так просто :) ... Сервер-то получит от клиента номер ордера в текущей workarea, который может не совпадать с реальным, так что все-равно нужно или имена тэгов в LETOTAG хранить, или что-то другое

Pasha: Лучше действительно имена тегов хранить в LETOTAG А для исключения излишней передачи сохранять текущий индекс в AREASTRU, и не передавать его в других командах. а только в dbSetOrder() Пересматриваю код Во 1-х, я немного ошибся в hs_goto: Надо написать для go top hs_setscope( nUserStru, nId, .t.) dbGoTop() IF oArea:bFilter != Nil hs_setscope( nUserStru, nId, .f.) DO WHILE !Eof() .AND. !Eval(oArea:bFilter) dbSkip(1) ENDDO hs_clearscope(nUserStru, nId, .f.) ENDIF hs_clearscope(nUserStru, nId, .t.) и для bottom тоже, поправлю И у меня сомнения по поводу кода в hs_skip: dbSkip( nSkip ) IF oArea:bFilter != Nil IF nSkip > 0 DO WHILE !Eof() .AND. !Eval(oArea:bFilter) dbSkip(1) ENDDO ELSE DO WHILE !Bof() .AND. !Eval(oArea:bFilter) dbSkip(-1) ENDDO ENDIF ENDIF Если nSkip > 1 и установлен bFilter, то этот код отработает неправильно

Pasha: Уже почти весь код перенесен на С, осталось совсем немного Открытие/создание, и навигация Я перепишу hs_goto, ok ? Там можно немного оптимизировать go top/ go bottom с установленным filter, используя dbOrderInfo(SKIPEVAL,,, bFilter)/dbOrderInfo(SKIPEVALBACK,,, bFilter) Когда я у себя в программах стал использовать эту функцию, выигрыш в производительности был существенным, в разы в некоторых случаях

Pasha: Кстати, SKIPEVAL можно использовать и в hs_skip if bFilter # nil for i := 1 to nSkip dbOrderInfo(SKIPEVAL,,, bFilter) next endif

alkresin: Уже почти весь код перенесен на С, осталось совсем немного Открытие/создание, и навигация Некоторые вещи, в т.ч. открытие/создание, скорее всего, придется оставить на prg - т.к. на C уровне обработки ошибок ( аналога BEGIN SEQUENCE ... END SEQUENCE ) нет. Я перепишу hs_goto, ok ? Ok.

Pasha: alkresin пишет: на C уровне обработки ошибок ( аналога BEGIN SEQUENCE ... END SEQUENCE ) нет Не получится обрушение сервера при разных нестандартных ситуациях типа "data corruption" ? В этом случае надо как-то перехватывать такие ошибки

alkresin: Такие нестандартные ситуации случаются при реальном повреждении файлов, которые, по идее, использование сервера как раз и должно исключить. А то ведь есть и такие ошибки, которые не обрабатываются и на prg уровне - всякие internal error - особенно с индексами.

Pasha: Может стоит сделать вызов ParseCommand() на prg-уровне внутри BEGIN SEQUENCE/END ?

Pasha: Надо обязательно перехватывать data width error в leto_UpdateRec

Pasha: Извиняюсь, так и делается. То есть, такая ситуация блокируется уже на клиенте

Pasha: Переписал на C hs_goto DBOI_SKIPEVAL не стал использовать: во 1-х, он реализован не на уровне dbfRdd, а выше - для dbfcdx/dbfntx Во 2-х: выигрыш в производительности в своих программах я получил фактически за счет перевода кода в цикле по workarea на С-уровень, что и так уже сделано В hs_skip все в порядке, это меня бес попутал :) Как поступим с TagName ? Сейчас имя тега передается при каждой операции навигации по таблице Может действительно передавать его на сервер только в letoOrderListFocus ? И на сервере проблема с поиском тега будет решена

alkresin: Как поступим с TagName ? Сейчас имя тега передается при каждой операции навигации по таблице Может действительно передавать его на сервер только в letoOrderListFocus ? Вопрос неоднозначный. Сам акт приема-передачи ip-пакета отнимает сравнительно немалое время, поэтому, скажем, один пакет длиной 100 байт передается существенно быстрее, чем 2 по 50. Обычно ordSetFocus() вызывается не так часто, но это происходит, например, почти при каждом открытии файла - так что если передавать пакет при ordSetFocus(), то файлы будут открываться медленнее. И на сервере проблема с поиском тега будет решена Она будет просто перенесена из одной функции в другую. При обработке ordSetFocus() все равно придется это делать.

Pasha: alkresin пишет: Вопрос неоднозначный. Сам акт приема-передачи ip-пакета отнимает сравнительно немалое время, поэтому, скажем, один пакет длиной 100 байт передается существенно быстрее, чем 2 по 50. Кстати, о птичках :) Я заметил, что закрытие БД выполняется довольно медленно, поскольку при dbCloseAll() передается отдельный пакет close для каждой workarea. Можно ли сделать закрытие всех областей letodb одним пакетом ?

Pasha: Тогда добавляем имя тега в LETOTAG ? Поскольку в пакетах goto/skip/seek имя текушего тега уже передается, для поиска данных тега на сервере этой информации будет достаточно

alkresin: Можно ли сделать закрытие всех областей letodb одним пакетом ? Если написать leto_dbCloseAll() и предложить использовать ее вместо dbcloseall() Тогда добавляем имя тега в LETOTAG ? Да

Pasha: Переписал на C hs_skip, переделал поиск тега на сервере по имени По поводу dbCloseAll: Сделать в leto_dbCloseAll() закрытие только "своих" областей, а затем вызовом dbCloseAll() закрывать остальные ? Правда, может быть случай, когда клиент подключен боее чем к одному серверу

alkresin: Переписал на C hs_skip, переделал поиск тега на сервере по имени Отлично! А почему в mail list не шлете changelog ? Сделать в leto_dbCloseAll() закрытие только "своих" областей, а затем вызовом dbCloseAll() закрывать остальные ? Не понял. Каких "своих" ? А какие еще закрывает клиентская программа при помощи dbCloseAll() ?

Pasha: Я все свои изменения отправляю в mail list. Возврата нет. Они не проходят ? Проверил - у меня в адресной книге стотит letodb-developers-bounces@lists.sourceforge.net Наверное надо Letodb-developers@lists.sourceforge.net Эх, Семен Семеныч Отправил тест. Насчет своих, я имел в виду, что могут быть открыты workarea и с другими rdd

Pasha: Теперь получил свое же письмо

Pasha: Что-то я смотрю, установка set deleted не срабатывает Ставлю set deleted on, и удаленные записи видны. Не пойму, в чем дело

Pasha: Увидел Может добавить еще один байт установок к командам seek/skip/goto для флага deleted и убрать bDeletedOn из USERSTRU ?

alkresin: Ставлю set deleted on, и удаленные записи видны. Не пойму, в чем дело Если устанавливаете после присоединения, то надо leto_Setdeleted() использовать.

Pasha: А Ads как делает ? Там дополнительной команды нет, используется текущая установка клиента Может все-таки добавим 1 байт к пакету передачи ? Из тех же соображений, что незначительное увеличение размера пакета лучше, чем дополнительный пакет. Да и совместимость с существующим кодом сохранится У меня к примеру сплошь и рядом встречаются такие конструкции: Function SeekPers(nTab) Local lSD := Set(_SET_DELETED, .f.), lR, no := persons->(IndexOrd()) persons->(dbSetOrder(2)) lR := persons->(dbSeek(nTab)) persons->(dbSetOrder(no)) Set(_SET_DELETED, lSD) Return lR Это приведет к 2-м дополнительным пакетам для 1-й операции поиска

alkresin: А Ads как делает ? В ADS RDD специальная технология используется, добавленная David G.Holm именно для таких целей в set-модуль. В нашем случае, согласен, стоит передать лишний байт, в нем можно, используя битовые функции, передавать и set exact ( сейчас оно вообще не передается ), а для seek поместить и bsoftseek,bfindlast ( сейчас это 2 отдельных байта ).

Pasha: alkresin пишет: передавать и set exact set exact нужен для вычисления выражений, а они вычисляются не только для фильтра (3 операции навиации), но и при создании индекса. Значит, надо передавать и для createindex Смотрим, какие еще установки могут понадобиться на сервере. _SET_PATH, _SET_DEFAULT - наверное, не нужны HB_SET_DECIMALS - тоже на сервере нафик не нужен SET_DATEFORMAT SET_EPOCH нужен для вычисления DTOC. Поскольку в битовой струкруре эти установки не помещаются, да и это глобальные установки, которые вряд-ли динамически будут изменяться, можно передать их на сервер отдельной командой Поскольку в основном то, что было запланировано в начале февраля, уже сделано, предлагаю обсудить дальнейшие направления работ Мне кажется, можно сделать вот что (перечисляю и малозначительные, и важные пункты) - загрузка сервером некой dll, в которую пользователь мог бы добавлять свои udf для индексных выражений. Для пользователя будет проще пересобрать специально предназначенную для таких целей dll, чем пересобрать сервер - укаазание в скрипте сборки сервера кодовых страниц, для которых надо выдать Request - поддержка дополнительных числовых полей: '2', '4', а также полей VFP - надо переделать PutValue для мемо-полей - оптимизация relations: передача состояния дочерних областей прямо в leto_rec, запись их на клиенте в некую область данных, и затем использование в SELF_RELEVAL вместо передачи на сервер запроса на seek/goto - сделать leto_CloseAll() - как делать транзакции ? Для каждого юзера заводить временный dbf/fpt файл для журнала транзакций, и в каждую таблицу добавлять служебное поле, поскольку флаг deleted использовать не удастся Какой уровень транзакций ? Только read commited ? - вычисляемые поля. Здесь возникает вопрос, как вычислять на сервере выражения, которые содержат имена алиасов клиента Ведь на сервере имена алиасов свои. Можно это разрешать имена алиасов поиском "->" и заменой - может быть стоит сделать возможность открытия таблицы с ограниченным количеством полей Для каких-то выборок понадобятся не все поля, которые присутствуют в таблице, а какой-то их набор. Это был бы такой суррогат sql-запросов

alkresin: Из базовой функциональности осталась ( если я не упустил еще что-то ) реализация orderListClear. Несмотря на кажущуюся простоту, там есть неприятные моменты. После этого можно делать поддержку ntx. Думаю, для этого надо прописывать в серверном ini [DATABASE] ( вот к ним и подобрались :) ) и там помечать ее как ntx. Из перечисленных вами пунктов интересными и приоритетными лично для меня являются транзакции и, в какой-то степени, вычисляемые поля. leto_closeAll() сделать просто: { sendrecv( "close;all';" ); // что-то вроде bNotSendClose = TRUE; // Глобальная переменная в leto1.c, чтоб метод close не слал запрос на сервер hb_rddCloseAll(); bNotSendClose = FALSE; } Кодовые страницы, наверное, надо указать в .h все - пусть если кто хочет уменьшить вес сервера, убирает ненужные ( а они не много-то и весят ). А важными для меня целями, кроме транзакций, являются дополнительные процессы, чтоб передавать им на исполнение некоторые задачи ( индексирование, ... ) и server side процедуры.

alkresin: Реализация транзакций мне видится следующим образом: leto_BeginTransaction() просто устанавливает в TRUE какой-нибудь bTransActive. leto_PutRec(), если bTransActive == TRUE, не посылает изменения на сервер, а добавляет в специальный буфер. leto_CommitTransaction() отправляет содержимое буфера на сервер и устанавливает bTransActive в FALSE. Сервер обрабатывает буфер, пишет изменения в таблицы, попутно сохраняя где-то содержимое измененных полей, чтобы в случае чего откатить изменения.

Pasha: Т.е. read commited Такая реализация транзакций будет работать очень быстро, надежно, но есть и недостатки 1. Внутри транзакции на клиенте операция seek не сможет учитывать измененные записи, которые еще не переданы на сервер Ограничение не такое уже и сильное, можно пойти на него Для операций skip/goto можно сделать просмотр буфера перед посылкой запроса на сервер 2. Как внутри транзакции в этом случае формировать значения ключевых полей, если с одна таблица будет учавствовать в 2-х транзакциях с разных клиентов ? Это уже более существенно

alkresin: Внутри транзакции на клиенте операция seek не сможет учитывать измененные записи, которые еще не переданы на сервер Я бы даже не назвал это ограничением. Надо просто корректно подготавливать выполнение транзакций: сначала найти все записи, которые будут изменены, заблокировать их, а потом выполнять транзакцию, иначе серверу относительно часто придется выполнять rollback ( если нужную запись не удалось заблокировать ). ADS, например, так и советует делать, они даже ограничивают выполнение блокировок во время транзакций и запрещают разблокировки. Как внутри транзакции в этом случае формировать значения ключевых полей, если с одна таблица будет учавствовать в 2-х транзакциях с разных клиентов ? Поясните на примере. Я пока не понял, в чем проблема.

alkresin: Кстати, учитывая то, что все команды доступа к данным выполняются в настоящий момент последовательно в одном потоке, правильнее определить уровень изоляции как serializable, т.е. самый высокий :).

Pasha: Я имел в виду одновременное получение значения ключа: dbGoBottom() nKey := Key + 1 begin transaction dbAppend() Field->Key := nKey ... Может случиться коллизия, когда 2-й клиент получит такое же значение ключа, пока 1-й не закончил транзакцию

Andrey: Не забудьте сделать еще запуск letodb.exe как службу !!! А то замучишься потом его запускать самостоятельно. А вообщето неплохо бы сделать прогу, которая занимая мало место в памяти на сервере, слушала бы Port = 2812 указанный в letodb.ini и при обращении к этому порту с любого клиента, поднимала бы сам letodb.exe А в самом letodb.exe предусмотреть выгрузку из памяти если все клиенты прекратили работу с БД. И тогда удаленно можно было бы редактировать letodb.ini

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

alkresin: Добавил поддержку DBFNTX. Чтобы сервер работал с этим драйвером, надо написать в letodb.ini: DEFAULT_DRIVER = NTX В самом ближайшем будущем добавлю в ini [DATABASE], чтобы устанавливать ntx не для всех данных, а для определенных каталогов.

alkresin: Теперь можно писать в ini: [DATABASE] DataPath = /some_db Driver = NTX чтобы определить каталог с данными /some_db, файлы в котором надо открывать через DBFNTX Сегодня, если не обнаружатся вдруг ошибки, выложу новый build.

gfilatov: alkresin пишет: выложу новый build Выложил готовую к использованию полную сборку LetoDB build 0.5 по адресу: http://minigui.mylivepage.ru/file/?fileid=4909 Результаты тестов для этой сборки: Test 1 Finished in 83.43 seconds Test 2 Finished in 0.55 seconds Test 3 Finished in 8.08 seconds Test 4 Finished in 7.96 seconds Расшифровка тестов: 1) добавление 200 000 записей и их заполнение произвольными данными 2) индексирование по числовому полю 3) позаписное перемещение через всю базу без использования индексов 4) позаписное перемещение через всю базу с использованием индекса Итоговый размер базы: 11,2 МБ Все тесты проводились на виртуальном (RAM) диске

alkresin: Фантастика! У вас там робот автоматом отслеживает релизы и делает сборки ? Я только несколько минут назад файлы выложил ...

Andrey: gfilatov пишет: Все тесты проводились на виртуальном (RAM) диске Не совсем понятно ! Что на сервере был создан виртуальный диск и на нем тестировалось ? Тогда это не есть хорошо ... Это не реальная ситуация ! Нужно тестировать на реально-работающем сервере, когда 10-15 клиентов сидят не только в этой задачи, но и в других.

gfilatov: Andrey пишет: Что на сервере был создан виртуальный диск и на нем тестировалось ? Все тесты проводились на виртуальном (RAM) диске на локальной машине Andrey пишет: Тогда это не есть хорошо ... Это не реальная ситуация ! Согласен. Но никто и не будет на сервере добавлять 200 тысяч записей за один раз, как в 1-м тесте

Andrey: Я попробую, чуть попозже !

Pasha: Для xHarbour-пользователей прийдется пересобрать билд, так как надо добавить функцию hb_strncpyLower

alkresin: Да, сегодня сделаю build6. Эту hb_strncpyLower я вообще убрал, заменил вызовами strncpy() и hb_strLower(). Ее, как выяснилось, нет не только в xHarbour, но и в летнем ( последнем официальном ) релизе Harbour.

alkresin: Выложил исправленный build6

gfilatov: alkresin пишет: Выложил исправленный build6 Выложил готовую к использованию полную сборку LetoDB build 0.6 (ровно 1000,00 КБайт) по адресу: http://minigui.mylivepage.ru/file/?fileid=4910 LetoDB Build 6 ( 27.03.2008 ) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [-] hb_strncpyLower() has been removed, because, as it appears, it is absent in xHarbour and current official Harbour release [+] Added support for additional field types: HB_FT_INTEGER HB_FT_DOUBLE HB_FT_FLOAT HB_FT_DAYTIME HB_FT_MODTIME Александр, А версия сервера в этой сборке осталась старой - Leto DB Server v.0.5 Также желательно иметь пример использования дополнительных типов полей

alkresin: А версия сервера в этой сборке осталась старой - Leto DB Server v.0.5 Забыл поправить. Ну и ладно, на этой стадии - не страшно. Также желательно иметь пример использования дополнительных типов полей Это к Паше. Я сам дополнительные типы не использую, и другим не советую :)

Pasha: Харбор поддерживает двочные поля следующих типов: (по формату dbCreate/dbStruct - name, type, len, dec) Дата: "D", 3 "D", 4 Дата в формате 3 или 4 байта "I", 2 - 16-ти битное целое со знаком, тип может быть также "2" "I", 4 - 32-ти битное целое со знаком, или тип "4" "I", 8 - 64-ти битное целое со знаком "8", 8, ndec - тип double (8 байт) "B", 8, ndec - аналогично "@", 8 - дата и время, размер 8 байт "T", 8 - аналогично дата и время "T", 4 - время в 4-х байтовом формате Преимущества двоичных типов: 1. Компактная запись данных. Особых причин использовать в 21-м веке архаичный текстовый формат эштон-тейт 80-х годов прошлого века сейчас нет :) 2. Возможность открывать dbf-формат скажем vfp Недостаток: 1. Нет возможности прямо указать размер поля для вывода на экран, поэтому используется мамксимальный размер текстового представления соответствующего типа 2. Прочие (помимо харбора) программные продукты могут не прочитать такой формат В харборе поддержка этих типов данных появилась давно, сейчас их можно использовать в letodb Правда, в билд 6 попали ошибки, которые я пофиксил только сейчас Насчет примера использования - это федь фича не letodb, а харбора, примеры должны быть в tests Если кратко: dbCreate(cPath + 'dtest.dbf', {; {'D3', 'D', 3, 0}, {'S1', 'C', 10, 0},; {'D4', 'D', 4, 0}, {'S2', 'C', 10, 0},; {'D8', 'D', 8, 0}, {'S3', 'C', 10, 0},; {'I4', 'I', 4, 0}, {'I2', '2', 2, 0}, {'F4', '8', 8, 2} }) dbUseArea(.t.,, cPath + 'dtest') dbAppend() ? I4 Field->D3 := Date() Field->S1 := '11' Field->D4 := Date() + 1 Field->S2 := '22' Field->D8 := Date() + 2 Field->S3 := '33' Field->I4 := 2 Field->I2 := -23 Field->F4 := 321.234 ? D3, I4, F4 dbCommit()

Vlad04: К Филатову. Выложил готовую к использованию полную сборку LetoDB build 0.6 (ровно 1000,00 КБайт) Сборка поддерживает xHarbour?

gfilatov: Vlad04 пишет: Сборка поддерживает xHarbour? Не проверял

alkresin: Сервер ( letodb.exe ) может быть собран чем угодно, а вот rdd - rddleto.lib, конечно же, должна быть сделана той же версией компилятора ( Harbour, C ), которой вы собираете свои программы.

gfilatov: Pasha пишет: в билд 6 попали ошибки, которые я пофиксил только сейчас Выложил готовую к использованию исправленную сборку LetoDB build 0.6 по адресу: http://minigui.mylivepage.ru/file/?fileid=4919 От себя добавил портированный в Minigui менеджер активных подключений сервера (вместе с исходниками) в дополенение к уже существующим консольному и оригинальному гуишному на Hwgui.

alkresin: Сделал транзакции - их еще проверять, поправлять и улучшать, но в первом приближении, вроде, работают. Напоминаю, что транзакция - это когда надо сделать одновременно несколько изменений в разных таблицах, так, чтобы прошло или все или ничего, чтобы не было потом несоответствий, а такое время от времени случается из-за сбоев в сети, ошибок и пр. Итак, делаем: leto_BeginTransaction() // Здесь, собственно, операции по изменению таблиц - // Append, Delete, Recall, Replace ... leto_CommitTransaction( [lUnlockAll] ) Чтобы не наделать ошибок, необходимо четко представлять себе, как это работает. Все операции по изменению таблиц ( append, delete, recall. replace ) реально осуществляются только во время leto_CommitTransaction(). Значит, если у вас: leto_BeginTransaction() select a rlock() replace xxx with 1 go top ... leto_CommitTransaction() то сначала исполнится go top, а после ( если блокировка прошла успешно ) - replace. Параметр lUnlockAll у leto_CommitTransaction(), по умолчанию - .T., указывает, надо ( .T. ) автоматически разблокировать все записи после выполнения транзакции, или нет, т.е. unlock'и делать не обязательно.

Pasha: alkresin пишет: Сделал транзакции Впечатляет, особенно скорость разработки. Скажу пару слов от себя. В отличие от традиционных транцакций, в letodb Александр реализует другой принцип, когда транзакциями занимается не сервер, а клиент При этом во время транзакции данные на сервер не передаются совсем, а передаются только при commit transaction Операция rollback на сервере не нужна вообще, так как неудачную транзакцию сервер и не увидит Преимущества такого подхода видны невооруженным глазом Есть и недостатки, куда же без них Если на сервере реализовывать целостность ссылок, foreign key, то на сервере надо тоже предусматривать возможность отката транцакции Александр, а может быть задействовать autoinc-поля ? Харбор их поддерживает, осталось поднять в letodb Но тода при добавлении записей во время транзакции надо получать значения этих полей с сервера

alkresin: Операция rollback на сервере не нужна вообще, так как неудачную транзакцию сервер и не увидит Не совсем так. Сервер увидит неудачную транзакцию, если, например, в клиентской программе не будет проверки блокировок ( значения, возвращаемого rlock() ). Rollback там не делается, потому что принятый пакет с изменениями сначала разбирается, наличие блокировок проверяется и потом, если все в порядке, все данные нормальные и проблем не ожидается, производится непосредственно запись в таблицы. Если на сервере реализовывать целостность ссылок, foreign key, то на сервере надо тоже предусматривать возможность отката транцакции Можно так же, как описано выше, предварительно проверять принятые данные, тогда rollback не понадобится. Но тода при добавлении записей во время транзакции надо получать значения этих полей с сервера Я думал, как можно делать такого рода вещи. Это ведь, чтобы использовать значения этих полей для записи в другие таблицы во время транзакции, верно ? Можно будет реализовать функции типа leto_fieldget( numfield, num_slot ) и leto_fieldput( numfield, num_slot ), которые во время транзакции будут включать в пакет соответствующие команды, и сервер, встретив эти команды, запишет в какой-то слот значение поля numfield в случае leto_fieldget и, соответственно, из слота в указанное поле в случае leto_fieldput.

Andrey: gfilatov пишет: Выложил готовую к использованию исправленную сборку LetoDB build 0.6 по адресу: Вопрос к Григорию: почему при запуске letodb.exe нет иконки в трее и нет вообще никакого окна от него ? Это сделано специально ? И на чем была проведена сборка ? Т.е. если на Харборе, то будет ли нормально работать хХарбор ? Или под свои программы на хХарборе нужно самостоятельно делать сборку letodb.exe ?

gfilatov: Andrey пишет: почему при запуске letodb.exe нет иконки в трее и нет вообще никакого окна от него ? Так задумано разработчиками сервера, для доступа к внутренней информации сервера служит дополнительная утилита manage.exe Andrey пишет: на чем была проведена сборка ? Использован Харбор. Andrey пишет: будет ли нормально работать хХарбор ? alkresin пишет: Сервер ( letodb.exe ) может быть собран чем угодно, а вот rdd - rddleto.lib, конечно же, должна быть сделана той же версией компилятора ( Harbour, C ), которой вы собираете свои программы. Думаю, что ответ Александра является исчерпывающим

Andrey: gfilatov пишет: Так задумано разработчиками сервера, для доступа к внутренней информации сервера служит дополнительная утилита manage.exe А как узнать версию сервера ? Это же нужно периодически для замены. Если бы сервер сидел в трее, то можно было бы вызывать его и менять настройки его. А так нельзя !!!

Pasha: Как настроить на сервере кодовую страницу и другие параметры по умолчанию ? Codepage необходим для вычисления upper(), например, в фильтрах Я вижу в варианта: 1) Добавить codepage в PUSERSTRU (вместе с set exact, set dateformat etc), и отрабатывать перед каждой операцей, в которой вычисляется макрос или блок кода 2) Добавить глобальные настройки в letodb.ini Можно реализовать оба варианта, или один из двух Как лучше ?

alkresin: Оба. Codepage, наверное, стоит передавать на сервер один раз с intro.

Pasha: Александр, у меня появилось такое предложение Что если сделать кеширование dbSkip(-1) аналогично dbSkip(1) ? Это нужно для оптимизации TBrowse и прочих гридов Процедура заполнения экрана следующая: сначала вызовами dbskip(1) определяется количество строк грида, затем следует несколько вызовов dbSkip(-1), по которым уже заполняется экран Если сделать writelog в leto_Skip, то получается такая картина: 2565;1;1;podrp;A; 2565;1;12;podrp;A; 2565;-1;19;podrp;A; 2565;-1;18;podrp;A; 2565;-1;17;podrp;A; 2565;-1;15;podrp;A; 2565;-1;14;podrp;A; 2565;-1;13;podrp;A; 2565;-1;12;podrp;A; 2565;-1;11;podrp;A; 2565;-1;10;podrp;A; 2565;-1;9;podrp;A; 2565;-1;8;podrp;A; 2565;-1;7;podrp;A; 2565;-1;6;podrp;A; 2565;-1;5;podrp;A; 2565;-1;4;podrp;A; 2565;-1;3;podrp;A; 2565;-1;2;podrp;A;

alkresin: Процедура заполнения экрана следующая: сначала вызовами dbskip(1) определяется количество строк грида, затем следует несколько вызовов dbSkip(-1), Значит, надо. Только тогда обязательно и другую штуку надо сделать - запоминать в LETOAREA время получения кэша, и если оно превышает какую-то константу ( 1с, например, ) и таблица открыта в shared режиме, обновлять кэш. Это в любом случае надо было делать, а при кэшировании dbskip(-1) - тем более, иначе можно долго так по кэшу ходить, в то время как данные давно изменились.

Pasha: По поводу SET_EXACT. А в каких случаях клиент должен устанавливать его на сервере, кроме как при выполнении макросов, заданных клиентом (фильтров, индексных выражений, условий индекса) ? Я не подумал, что установка этого флага может быть опасной для сервера, поскольку часть его кода остается на prg-уровне. Может быть, просто восстанавливать его значение после использования для фильтра/индекса ? Я пропустил установку параметров окружения клиента для leto_Goto Надо еще добавить в UpdateRec, поскольку во время этой операции обновляются ключи индекса

alkresin: По поводу SET_EXACT. А в каких случаях клиент должен устанавливать его на сервере, кроме как при выполнении макросов, заданных клиентом (фильтров, индексных выражений, условий индекса) ? Т.е., при всех операциях перемещения, если установлен фильтр, и при update, если есть for в индексе ( но проще и быстрее set exact лишний раз установить, чем это проверять ). Может быть, просто восстанавливать его значение после использования для фильтра/индекса ? Конечно.

gfilatov: Выложил готовую к использованию полную сборку LetoDB CVS build 0.6 по адресу: http://minigui.mylivepage.ru/file/?fileid=5167 Эта сборка поддерживает транзакции

gfilatov: Выложил готовую к использованию полную сборку LetoDB CVS build 0.7 по адресу: http://minigui.mylivepage.ru/file/?fileid=5236 Эта сборка включает в себя два аналогичных менеджера подключений, собранных с помощью HWGui и MiniGui

Andrey: Вопрос на засыпку ???? А когда будет реализована шифрация текстовых данных !!! Чтоб они в базе шифрованные хранились !!! У себя в программе шифруешь запрос, отправляешь на сервер, сервер выдает шифрованные данные, далее у себя в программе их дешифруешь и потом показываешь ! Только нужно бы предусмотреть подключение своих алгоритмов шифрации-дешифрации, включая железных алгоритмов (типа ключа HASP HL) . Может кто-то по другому мыслить, так давайте обсуждать это. Но передачу данных по сети нужно шифровать. Да и хранить БД-нужно тоже шифрованную. Уже сама жизнь заставляет.

Andrey: Тестирую сервер. Столкнулся с непонятной вещью при использовании Манеджера из minigui ..... Почему всех программ по 2 штуки ???

gfilatov: Andrey пишет: Столкнулся с непонятной вещью Andrey Логика работы обоих менеджеров (HwGUI и MiniGUI) абсолютно одинакова: они получают информацию от сервера LetoDB. По ходу, под Win98 удвоения программ не наблюдалось...

Andrey: gfilatov пишет: По ходу, под Win98 удвоения программ не наблюдалось... Пробовал на 2-х машинах под ХР.... Везде по 2-копии....

PSP: У одной имя manage.exe, а у другой - manager.exe

Andrey: Взялся тестировать сервер на локальной сети микрорайона, и вышел облом...... Сервер поставил у себя, а приложение отдал другу через несколько домов. У меня стоит Outpost Firewall Pro ver. 4.0 Настроил разрешение для работы как FTP-сервер. Мой тестовый пример у меня запускается, а у друга нет. Может дело в разных IP-адресах ???? У него адрес 10.60.232.15, у меня 10.60.202.15 Тестовый пример: Function Main() LOCAL cTable, nConnect // My host base cTable := "//10.60.202.15:2812/spiski.dbf" * Можно пользоваться и названием компа-сервера *cTable := "//SERVER2008:2812/spiski.dbf" //server host REQUEST LETO RDDSETDEFAULT( "LETO" ) CLEAR SCREEN @ 0,0 say "Open DBASE: "+cTable nConnect := leto_Connect( cTable ) ?? nConnect IF nConnect == 0 USE ( cTable ) NEW Browse() USE ELSE ALERT( "Server LetoDB not run !; "+cTable ) ENDIF Return nil Отключал у себя полностью Outpost Firewall, все равно не помогает.... Кстати пробовал пинговать комп, по этому адресу 10.60.232.15, не видется в сети.... Может сетка так настроена ? Где и что неправильно .....

Pasha: Andrey пишет: Кстати пробовал пинговать комп, по этому адресу 10.60.232.15, не видется в сети.... Может сетка так настроена ? А как она настроена ? Какие вообще сетевые средства работают ? Только ftp ? Компьютер не пингуется, и о чем дальше говорить ? Надо, чтобы пинговался И можно попробовать использовать другой порт, вместо 2812 То, что компьютеры находятся в разных подсетях, роли не играет

Andrey: Pasha пишет: А как она настроена ? Какие вообще сетевые средства работают ? Только ftp ? Компьютер не пингуется, и о чем дальше говорить ? Надо, чтобы пинговался Так кто-же знает как настроена сеть .... Провайдер знает, а он фиг ответит.... Буду долбать его... Pasha пишет: То, что компьютеры находятся в разных подсетях, роли не играет Понял, спасибо !

Snake: imho если netmask стоит по умолчанию - 255.255.255.0 - и не будет видеть, надо ставить чн типа 255.255.0.0

Andrey: Короче говоря это ПРОВАЙДЕР зарубил все порты, придется по другому тестировать ..... Вопрос самый главный: Как можно открыть одновременно базы на сервере и базы на локальной машине ??? Мне же нужно выборку делать, скидывать свое... да мало ли для чего.

sashaBG: Leto_Frename( _Server + 'smplan.DBF' , _Server +'temp.dbf' ) msginfo(str(leto_ferror())) // тут получается ошибка 53

Pasha: Leto_Frename( _Server + 'smplan.DBF' , _Server +'temp.dbf' ) 2-й параметр (новое имя) надо задавать без указания сервера: _Server

Andrey: Вопрос самый главный: Как можно открыть одновременно базы на сервере и базы на локальной машине ???

Pasha: Таблицы на сервере открывать через LETO, локально - через DBFCDX Можно конечно на каждом клиенте тоже запустить LetoDB, и стучаться к нему локально через 127.0.0.1, но это будет уже извращение.

Andrey: Pasha пишет: локально - через DBFCDX А как ? Синтаксис команды можно привести ?

Pasha: синтаксис традиционный для клиппера REQUEST LETO, DBFCDX USE t1 VIA LETO USE t2 VIA DBFCDX Естественно, надо указать путь доступа для таблиц на сервере или локально

Andrey: Спасибо !!! А можно сейчас открывать на сервере NTX файлы ? А одновременно NTX и CDX ?

Pasha: Сейчас на сервере можно задать либо глобальную настройку - параметр DEFAULT_DRIVER, либо указать несколько БД (в разных каталогах), и для каждой указать параметры DATAPATH и DRIVER Пример: [DATABASE] DATAPATH=c:\data\b1 DRIVER = cdx [DATABASE] DATAPATH=c:\data\b2 DRIVER = ntx При открытии таблицы сервер по каталогу находит БД, и использует нужный драйвер

Pasha: Добавил функцию LETO_SUM(cField, [cFilter], [ScopeTop], [ScopeBottom]) Функция суммирует поле cField для записей, удовлетворяющих условию фильтра и scope

a_sidorov: Несколько офисов по Москве. Есть желание объединить. Запустил сервер на другой машине, внес изменения, но с ходу не очень получилось. На какие грабли наступаю: 1. При отсутствии файла letodb.ini (ну ошибся в имени, с кем не бывает) файл открывается по полному пути. Если поставить вызов leto_file(), то возвращает .f. (не работает), при этом все начинает глючить. Файл открывается с вероятностью 50%, выдавая случайным образом ошибку. Надо бы исправить. При открытии файла идет ошибка Error LETO/1021 Data type error: -002 2. Указываю в letodb.ini (уже делаю тест на локалке) EnableFileFunc = 1 DEFAULT_DRIVER = NTX DataPath = f:/ftest Оказавается, путь к dbf должен указываться с IP адресом, а к индексному файлу – без IP адреса. Но ведь, как правило, настройка путей прописывается в одном месте, кроме того, нужно проверять наличие файла на сервере. Придется после проверки наличия файла функцией leto_file(fname) удалять из fname IP адрес, например Stat func DelIPpath(fname) return if(Left(fname,2)=="//",substr(fname,at("/",substr(fname,3))+2),fname) Опять - почему это не делать на сервере? 3. Активно использую функцию XUPPER для поднятия русских букв в верхний регистр. Func XUpper( String ) Retu CharRepl( 'abcdefghijklmnopqrstuvwxyzабвгдеёжзийклмнопрстуфхцчшщьыъэюя',; String,; 'ABCDEFGHIJKLMNOPQRSTUVWXYZАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЫЪЭЮЯ' ) Приехали и встали. На сервере ее нет. Функция Upper() не поднимает русские буквы. Общее впечатление – сыровато с точки зрения – шаг влево, шаг вправо. Переделки сетевой задачи на NTX небольшие: в функции сетевого открытия проверяем наличие в имени файла “//“ и открываем файл VIA LETO. И убираем IP из имени файлов индексов для серверных файлов. Все остальные файлы, в имени которых нет “//” (в том числе локальные) открываются как NTX по умолчанию. В Нужно что-то делать с функциями в индексе. Как минимум пара функций есть своих кроме XUpper(). Пока стою и решаю, идти ли дальше.

Pasha: 1. При отсутствии letodb.ini применяются стандартные настройки, где параметр EnableFileFunc выключен Впрочем, я пересмотрю leto_file(). На SF форуме Leonardo Machado тоже на нее жалуется, хотя у меня его пример работает 2. Параметры соединения: IP:port необходимы только при открытии таблицы, при открытии индекса они не нужны. Так что логика в этом есть. Впрочем, это можно обсудить 3. Вопрос про UDF уже здесь обсуждался, и пришли к выводу, что такие функции, или request для стандартных Харбор-функций, пользователью надо включать в тело server.prg. Ведь процедура сборки сервера простейшая Кстати, русские кодовые страницы на сервере подликовываются, и upper должен работать корректно

a_sidorov: Фукция Indexkey() возвращает правильно только первые два индексных выражения (проверял на NTX), вместо третьего идет код. Сам индекс поддерживается. Пробовал переставлять второй и третий индекс, возвращает либо код 10 либо код 55, в зависимости от того, какой индекс стоит третьим.



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