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

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

Pasha: Немного доработал документацию к letodb

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

Andrey: А почему ссылки на LetoDB нет на самом главном сайте: http://harbour-project.sourceforge.net/download_contrib.html Это же большой промах...

Pasha: Andrey пишет: А почему ссылки на LetoDB нет на самом главном сайте: http://harbour-project.sourceforge.net/download_contrib.html Это же большой промах... Там перечисляются только библиотеки, которые входят в поставку Harbour. А letodb - это отдельный проект. У меня была мысль передать letodb в harbour\contrib, как один из вариантов, поскольку положение с проектом сейчас явно ненормальное, даже если кто-то захочет присоединиться к проекту - он не сможет этого сделать. Но тогда может быть прекращена поддержка клиентской библиотеки для xHarbour, да и делать это без согласия автора проекта не хотелось бы.

Andrey: Все равно надо там разместить ссылки на LetoDB и выложить что-нибудь, пускай знают что есть классный продукт под Harbour. И решить вопрос с автором проекта...


Pasha: Dima пишет: Возможно тут дело не в LetoDB а в TSBrowse Скорее всего, надо сделать что-то вроде: oB:bTagOrder := {|| ordNumber()} для восстановления тэга при получении фокуса

Pasha: Andrey пишет: Все равно надо там разместить ссылки на LetoDB и выложить что-нибудь, Разве что здесь: http://harbour-project.sourceforge.net/third-party.html#RDD

Andrey: Pasha пишет: Разве что здесь: http://harbour-project.sourceforge.net/third-party.html#RDD Да хотя бы туда.

alex_II: Pasha пишет: Скорее всего, надо сделать что-то вроде: oB:bTagOrder := {|| ordNumber()} для восстановления тэга при получении фокуса Спасибо за подсказку, помогло! Проверил вариант без letoDB, получил тот же глюк, значит дело в TSBrowse

Pasha: Новости проекта: 1. Если открывается большая БД, содержащая много (десятки и сотни) таблиц, появилась возможность открывать все таблицы одним запросом, а не множеством запросов, каждый отдельный для команды use Для этого надо вызвать udf-функцию UDF_OpenTables, и передать ей массив с описанием открываемых таблиц. Эта функция вернет массив строк, каждый элемент которого надо передать команде use вместо имени таблицы. При этом use не будет делать запрос к серверу, а заполнит данные rdd, используя элемент массива. Использование алиаса при этом обязательно. Пример: if leto_UDFExist( "UDF_OpenTables" ) aAreas := leto_UDF( ""UDF_OpenTables"", {{"table1",, .t.}, {"table2",, .t.}, {"table3",, .t.}} ) use (aAreas[1]) alias table1 shared new use (aAreas[2]) alias table2 shared new use (aAreas[3]) alias table3 shared new else use table1 alias table1 shared new use table2 alias table2 shared new use table3 alias table3 shared new endif 2. Добавлена функция на сервере leto_RecLockList( nUserStru, aRecNo ) --> lSuccess Функция leto_RecLockList блокирует записи с номерами, указанными в массиве aRecNo. Если блокировка какой-либо записи не удалась, блокировки снимаются, и возвращается результат .F. Эту функцию можно вызывать на сервере в модуле letoudf.prg, или с клиента вызовом leto_UDF( "leto_RecLockList", aRecNo ) Вместо множества вызовов dbRLock можно использовать один вызов leto_RecLockList. У меня при некоторых операциях блокируется свыше тысячи записей, и новая функция позволит резко сократить количество запросов к серверу.

Andrey: Хорошее решение ! Классно !

Pasha: Вопрос касается выделения памяти для списка блокированных записей в letodb сервере В dbfcdx/dbfntx список построен как простой массив значений типа unsigned long (это номера блокированных записей) При блокировке записи память под массив перевыделяется (его размер увеличивается), при снятии блокировки - размер уменьшается В letodb сделано примерно аналогично, только память под массив увеличивается порциями по 50 элементов, а при снятии блокировки - размер не уменьшается. В letodb это может привести к коллизиям при многопоточной обработке: при перевыделении памяти адрес массива может измениться, а в это время другой поток может к нему обращаться. Предложите другой способ организации этого списка. Пока я вижу только простейший список со ссылкой на следующий элемент. Может быть есть способ поэффективнее ?

Pasha: Остановился на однонаправленном отсортированном списке. Структура такая: typedef struct { ULONG ulRecNo; PLETO_LOCK_ITEM pNext; } LETO_LOCK_ITEM, *PLETO_LOCK_ITEM; typedef struct { BOOL bLocked; PLETO_LOCK_ITEM pItem; } LETO_LOCK_LIST, *PLETO_LOCK_LIST; 3 функции для нее: Поиск в списке static BOOL letoIsRecInList( PLETO_LOCK_LIST pLockList, ULONG ulRecNo ) Добавление в список static void letoAddRecToList( PLETO_LOCK_LIST pLockList, ULONG ulRecNo ) Удаление из списка static void letoDelRecFromList( PLETO_LOCK_LIST pLockList, ULONG ulRecNo ) Ну и функция очистки всего списка. Каждая функция перед тем, как работать со списком, выполняет цикл с проверкой pLockList->bLocked: static void letoLockWait( PLETO_LOCK_LIST pLockList ) { while( pLockList->bLocked ) ; } 2 последние функции перед добавлением/удалением элемента блокируют список: pLockList->bLocked = TRUE; После чего разблокируют его. Вопрос. Не может ли быть здесь коллизий при многопоточной работе ? Пусть один поток что-то делает со списком, и заблокировал его. Другой поток перед поиском в списке вызывает цикл letoLockWait( pLockList ); Зацикливания, даже теоретически, не произойдет ?

Pasha: Переделал списки блокированных записей, списки индексов, рабочих областей вместо массивов, которые могут перевыделяться в памяти, на однонаправленные списки. Но все-таки, меня терзают смутные сомнения. Если один поток что-то делает со списком, добавляет и в него элемент или удаляет, то надо на время операции блокировать список для доступа на чтение и запись другим потокам, во избежание неприятностей в виде гпф. А как это сделать ? Я в список добавляю 2 флага: bLockRead и bLockWrite: typedef struct { BOOL bLockRead; BOOL bLockWrite; ULONG ulSize; PLETO_LIST_ITEM pItem; } LETO_LIST, *PLETO_LIST; и перед доступом к списку проверяю эти флаги: void letoWaitWrite( PLETO_LIST pLockList ) { while( pLockList->bLockWrite || pLockList->bLockRead ) pLockList->bLockWrite += 0 ; } void letoWaitRead( PLETO_LIST pLockList ) { while( pLockList->bLockWrite ) pLockList->bLockWrite += 0 ; } Но эта зараза, а именно компилятор C, оптимизирует эти циклы, и ничего не делает. Специально дизассемблировал на предмет посмотреть. Оно не понимает, что к структуре имеет доступ другой поток, который может изменять значение флагов Как сделать блокировку списка ? Может быть, у потоков есть стандартный механизм для этого ?

Andrey: Pasha спасибо за совершенствование LetoDB. Жалко что не могу помочь в таких сложных решениях. Поспрашивай, может на других Си-шных форумах помогут.

PSP: Ну, а если в тело цикла вставить дополнительные строки, не нарушающие логики, которые смогут убедить компилятор не оптимизировать цикл? К примеру: [pre2] typedef struct { BOOL bLockRead; BOOL bLockWrite; int nTemp; ULONG ulSize; PLETO_LIST_ITEM pItem; } LETO_LIST, *PLETO_LIST; void letoWaitWrite( PLETO_LIST pLockList ) { while( pLockList->bLockWrite || pLockList->bLockRead ) { pLockList->bLockWrite += 0 ; if ( pLockList->nTemp ) { pLockList->nTemp := 0 ;} else { pLockList->nTemp := 1 ;} } } [/pre2] Upd: опечатка. Вместо pLockList->i д.б. pLockList->nTemp. Исправил.

santy: Паша, а если попробовать использовать мьютекси. Примеры можна посмотреть здесь : http://habrahabr.ru/post/72929/ http://www.sofmos.com/lyosha/Articles/multithreading1.html http://docs.oracle.com/cd/E19253-01/816-5137/sync-12/index.html Пример использования мьютексов к списку: http://maxim.int.ru/bookshelf/PthreadsProgram/htm/r_27.html

Pasha: santy пишет: Паша, а если попробовать использовать мьютекси. Спасибо, это то что надо. Я чувствовал, что делаю что-то не то. Надо использовать мютексы.

AlexMyr: Хочу узнать дату последнего обновления базы, dbinfo(4) возвращает пустую дату. Что делать?

Pasha: Сейчас LastUpdate не передается с сервера. Надо будет добавить. Только это связано с изменением протокола, вот думаю, как сделать, чтобы новые версии сервера и клиента при этом работали со старыми.

AlexMyr: Pasha пишет: Сейчас LastUpdate не передается с сервера. Надо будет добавить. Спасибо, работает!

AlexMyr: Паша! Команда append from я так понимаю не сработает с letodb сервера на локальный диск, надо через массив записи переганять?



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