Автор | Сообщение |
|
| |
Пост N: 2728
Зарегистрирован: 17.05.05
|
|
Отправлено: 12.03.13 11:27. Заголовок: Leto DB Server (продолжение 10) (продолжение)
Продолжаем тут
| |
|
Ответов - 191
, стр:
1
2
3
4
5
6
7
8
9
10
All
[только новые]
|
|
|
| постоянный участник
|
Пост N: 579
Зарегистрирован: 17.02.12
|
|
Отправлено: 16.04.15 08:26. Заголовок: alkresin, Pasha изви..
alkresin, Pasha извините, что достаю ..., но есть предложение добавить в letodb.ini режим AutoMakeDir = [0] \ 1 - автомат. создание директорий при создании таблицы. такой штукой пользуемся ~5 лет - очень упрощет код на клиенте Скрытый текст
FUNCTION hs_createtable( nUserStru, cCommand ) ... IF Lower(cName) = "/mem:" cDataPath := "" cName := Substr(cName, 2) ELSE cDataPath := leto_GetAppOptions( 1 ) ENDIF // IF ! empty(cDataPath) // cFileName := cDataPath + cName // ENDIF // _MakeDir_(cFileName) // // BEGIN SEQUENCE WITH { |e|break( e ) } ... STATIC FUNCTION _MakeDir_( cDBF ) LOCAL i, cCt, aCt := {} i := RAt(DEF_SEP, cDBF) cCt := Left(cDBF, i-1) DO WHILE ! hb_DirExists( cCt ) i := RAt(DEF_SEP, cCt) IF i == 0 ; EXIT ENDIF AAdd( aCt , subs(cCt, i+1) ) cCt := Left( cCt, i-1) ENDDO i := Len( aCt ) DO WHILE i > 0 cCt += (DEF_SEP + aCt[i--]) MakeDir( cCt ) ENDDO RETURN .T.
| возвращаюсь к наличию в letodb аналогов функций hb_fSetDateTime, hb_fGetDateTime. потестировал: Скрытый текст
FUNCTION UDF_fGetDateTime( nUserStru, cFile ) LOCAL dDate, cTime, lFile, cPath := leto_GetAppOptions(1) IF left(cFile, 1) == DEF_CH_SEP cFile := subs(cFile, 3) cFile := subs(cFile, At(DEF_CH_SEP, cFile)) cFile := StrTran(cFile, DEF_CH_SEP, DEF_SEP) cFile := subs(cFile, len(cPath)+1) ENDIF cPath += DEF_SEP lFile := file(cPath+cFile) IF lFile; hb_fGetDateTime(cPath+cFile, @dDate, @cTime) ENDIF RETURN { dDate, cTime } FUNCTION UDF_fSetDateTime( nUserStru, cFile, dDate, cTime ) LOCAL lFile, cPath := leto_GetAppOptions(1) IF empty(dDate); dDate := Date() ENDIF IF empty(cTime); cTime := Time() ENDIF IF ! '.' $ cTime; cTime += '.001' ENDIF IF left(cFile, 1) == DEF_CH_SEP cFile := subs(cFile, 3) cFile := subs(cFile, At(DEF_CH_SEP, cFile)) cFile := StrTran(cFile, DEF_CH_SEP, DEF_SEP) cFile := subs(cFile, len(cPath)+1) ENDIF cPath += DEF_SEP lFile := file(cPath+cFile) IF lFile; hb_fSetDateTime(cPath+cFile, @dDate, @cTime) ENDIF RETURN lFile
| работает хорошо, но как мне думается, наличие такого механизма в файловой части letodb (режим EnableFileFunc = 1) более правильное решение, которое позволит организовывать зеркальный letodb, получение изменений на localhost, в mysql, FTP, ... без открытия таблиц (по тэгу модификации dbgobottom, получение данного и закрытие таблицы), что упростит код на клиенте конечно вместо 2-х функций можно соорудить одну: leto_fDateTime(cFileName \ aFileName [, dDate \ .T. [, cTime ]]) leto_fDateTime(cFileName \ aFileName) - возвращает {dDate, cTime} или {{dDate, cTime}, ...} leto_fDateTime(cFileName \ aFileName, .T.) - ставит файлу\файлам дату, время сервера leto_fDateTime(cFileName \ aFileName, dDate, cTime) - - ставит файлу\файлам дату, время параметров наличие такого механизма позволит, попробовать использовать skipbuffer(LastRec()) с прочитанным целиком справочником и отключенной очисткой skipbuffer (вместо чтения в массив или memio) сейчас, в 2-х поточной версии letodb, работает механизм с открытием, ..., закрытием таблиц и набралось ~200 таблиц (только опрос - время) и приходится по клиенту размазывать (урезать) список, перед вых. формами весь, перед документом - связанное с этим докум., и .т.д.
| |
|
|
| moderator
|
Пост N: 925
Зарегистрирован: 06.07.06
|
|
Отправлено: 16.04.15 10:33. Заголовок: Вроде работают тепер..
Вроде работают теперь триггеры, но, учтите, располагаться сами функции должны в letoudf.hrb. Мне не понятно, почему вы все время говорите о letodb.hrb - файл с таким именем нигде в коде сервера не упоминается. SergKis пишет: цитата: | наверное, правильно, устанавливать "свой" триггер только для нужной области (с клиента) |
|
В смысле - для нужной таблицы ? Я тоже так думаю. Установка общего триггера довольно накладна - эта процедура вызывается при всех операциях со всеми таблицами. А вот насчет "с клиента" - не соглашусь. Триггер должен быть определен только на сервере, в этом весь его смысл - чтобы он работал независимо от того, что написано в клиентской программе.
| |
|
|
| постоянный участник
|
Пост N: 584
Зарегистрирован: 17.02.12
|
|
Отправлено: 16.04.15 10:59. Заголовок: alkresin letodb.hrb..
alkresin letodb.hrb - это описка, конечно letoudf.hrb цитата: | А вот насчет "с клиента" - не соглашусь. Триггер должен быть определен только на сервере |
| Здесь, мы друг друга не допоняли. Триггер(ы) определен(ы) ТОЛЬКО на сервере в letoudf.hrb, но активировать (нужный) триггер для нужной таблицы - с клиента, я это имел ввиду говоря "с клиента" Общий триггер, тоже полезная штука - сейчас (в 2-х поточной версии) работает общий и для всех таблиц заполняет поля обязательные (пост был выше) - нет мороки ставить\снимать для таблиц Если выбирать, какой предпочтительней, то по моей ситуации на сегодня лучше общий - переход на новую версию безболезненный Как разграничить алгоритмы ... ? Если в ini задан Trigger - то общий, иначе с клиента, что то типа leto_SetTrigger(...)
| |
|
|
| постоянный участник
|
Пост N: 586
Зарегистрирован: 17.02.12
|
|
Отправлено: 16.04.15 11:52. Заголовок: alkresin пишет:Вроде..
alkresin пишет: цитата: | Вроде работают теперь триггеры |
| туплю в SIXNSX было: /* * USE command with support for TRIGGER and PASSWORD clauses */ #command USE <(db)> [VIA <rdd>] [ALIAS <a>] [<nw: NEW>] ; [<ex: EXCLUSIVE>] [<sh: SHARED>] [<ro: READONLY>] ; [CODEPAGE <cp>] [INDEX <(index1)> [, <(indexN)>]] ; [TRIGGER <trig>] [PASSWORD <pass>] => ; [Sx_SetTrigger( TRIGGER_PENDING, <trig>, <rdd> ); ] <-trig-> ; [Sx_SetPass( <pass>, 1, <rdd> ); ] <-pass-> ; dbUseArea( <.nw.>, <rdd>, <(db)>, <(a)>, ; if(<.sh.> .or. <.ex.>, !<.ex.>, NIL), <.ro.> [, <cp>] ) ; [; dbSetIndex( <(index1)> )] ; [; dbSetIndex( <(indexN)> )] как ставить ? sele 0 HB_RddInfo( RDDI_PENDINGTRIGGER, 'my_Trigger', 'LETO' ) или HB_RddInfo( RDDI_PENDINGTRIGGER, 'my_Trigger', 'DBFCDX' ) dbUseArea(.F., 'LETO', ...) разъясните, пожалуйста и в чем разница RDDI_PENDINGTRIGGER и RDDI_TRIGGER ?
| |
|
|
| moderator
|
Пост N: 926
Зарегистрирован: 06.07.06
|
|
Отправлено: 16.04.15 12:29. Заголовок: SergKis пишет: Триг..
SergKis пишет: цитата: | Триггер(ы) определен(ы) ТОЛЬКО на сервере в letoudf.hrb, но активировать (нужный) триггер для нужной таблицы - с клиента, я это имел ввиду говоря "с клиента" |
| Насколько я понимаю предназначение триггеров, они должны работать всегда, независимо от того, активирует их или нет клиентская программа. Если вы ставите, например, триггер на добавление записи в table1 - чтобы при этом и в table2 что-то добавлялось, а в table3, например, увеличивался счетчик - то важно, чтобы это работало всегда, иначе пострадает целостность базы данных. Обеспечение целостности данных, целостности связей между таблицами, как я понимаю, одна из важнейших задач триггеров. цитата: | как ставить ? sele 0 HB_RddInfo( RDDI_PENDINGTRIGGER, 'my_Trigger', 'LETO' ) или HB_RddInfo( RDDI_PENDINGTRIGGER, 'my_Trigger', 'DBFCDX' ) dbUseArea(.F., 'LETO', ...) |
| О чем это вы ? Имя процедуры ведь на сервере в letodb.ini указывается. цитата: | и в чем разница RDDI_PENDINGTRIGGER и RDDI_TRIGGER ? |
| Честно говоря, понятия не имею.
| |
|
|
| постоянный участник
|
Пост N: 588
Зарегистрирован: 17.02.12
|
|
Отправлено: 16.04.15 12:58. Заголовок: alkresin пишет:О чем..
alkresin пишет: цитата: | О чем это вы ? Имя процедуры ведь на сервере в letodb.ini указывается. |
| Не увидел в текстах, где установка, потому и непонятка возникла, если как было через ini, то пошел пробовать. Спасибо.
| |
|
|
| moderator
|
Пост N: 927
Зарегистрирован: 06.07.06
|
|
Отправлено: 16.04.15 13:54. Заголовок: По поводу RDDI_PENDI..
По поводу RDDI_PENDINGTRIGGER. Он используется в dbf1.c следующим образом: if( SELF_RDDINFO( SELF_RDDNODE( &pArea->area ), RDDI_PENDINGTRIGGER, pOpenInfo->ulConnection, pItem ) == HB_SUCCESS ) { if( HB_IS_STRING( pItem ) ) hb_dbfTriggerSet( pArea, pItem ); } if( ! pArea->fTrigger ) { if( SELF_RDDINFO( SELF_RDDNODE( &pArea->area ), RDDI_TRIGGER, pOpenInfo->ulConnection, pItem ) == HB_SUCCESS ) { if( HB_IS_STRING( pItem ) ) hb_dbfTriggerSet( pArea, pItem ); } } Т.е., при открытии таблицы сначала устанавливается он, а затем, если его не удалось установить (а это может произойти, если соответствующая функция не найдена), RDDI_TRIGGER. Мне не очень понятно, зачем это может понадобиться.
| |
|
|
| постоянный участник
|
Пост N: 590
Зарегистрирован: 17.02.12
|
|
Отправлено: 16.04.15 14:50. Заголовок: alkresin Спасибо..
alkresin Спасибо
| |
|
|
| |
Пост N: 18
Зарегистрирован: 06.12.14
|
|
Отправлено: 06.05.15 13:04. Заголовок: Возникла пара вопрос..
Возникла пара вопросов после крайнего обновления. Увидел что добавилась функция Udf_Exit() Если я правильно понимаю: Udf_Init() - вызывается как при запуске сервера так и при загрузке letoudf.hrb Udf_Exit() - вызывается только при остановке сервера, но не при выгрузке letoudf.hrb Есть ли возможность добавить, что-то типа Udf_Unload() - которая будет вызываться при выгрузке letoudf.hrb когда идет команда reload.
| |
|
|
| |
Пост N: 19
Зарегистрирован: 06.05.14
|
|
Отправлено: 06.06.15 16:36. Заголовок: Transaction
Я тестирую Leto_*Transaction: цитата: | USE (cPath + "Artikli1") ALIAS Artikli1 SHARED NEW VIA "LETO" USE (cPath + "Artikli2") ALIAS Artikli2 SHARED NEW VIA "LETO" FLock () SELECT Artikli1 Leto_BeginTransaction () GO TOP WHILE !Eof() Artikli2->(DBAppend()) Artikli2->a_naziv := Upper(a_naziv) Artikli2->a_naziv2 := Lower(a_naziv2) Artikli2->a_por := a_por + "ABC" ... SKIP END DO Leto_CommitTransaction () |
| Эта программа работает 73 секунд. Без Begin/EndTransaction работает 15 секунд. Почему это так, и может ли это быть ускорено? Спасибо, Ненад
| |
|
|
| |
Пост N: 4877
Зарегистрирован: 17.05.05
|
|
Отправлено: 06.06.15 16:43. Заголовок: nbatocanin Давно я ..
nbatocanin Давно я работал с LETO но попробуйте Leto_CommitTransaction () поставить до SKIP а Leto_BeginTransaction () перед Artikli2->(DBAppend())
| |
|
|
|
| |
Пост N: 20
Зарегистрирован: 06.05.14
|
|
Отправлено: 07.06.15 04:41. Заголовок: Dima пишет: Давно я..
Dima пишет: цитата: | Давно я работал с LETO но попробуйте Leto_CommitTransaction () поставить до SKIP а Leto_BeginTransaction () перед Artikli2->(DBAppend()) |
| Я пробовал, когда это сделать получается 790 секунд :(
| |
|
|
| постоянный участник
|
Пост N: 4231
Зарегистрирован: 12.09.06
|
|
Отправлено: 07.06.15 13:00. Заголовок: nbatocanin пишет: Я..
nbatocanin пишет: цитата: | Я пробовал, когда это сделать получается 790 секунд :( |
| Попробуйте тесты, которые я сделал и проверял. - https://cloud.mail.ru/public/Lr52/WR9soGyFn TEST_DBF.hbp - терминалка сделанная SergKis. Закачивает базу на сервер супер быстро. Сборка под МиниГуи для терминалки. DbftoServer.hbp - загрузка dbf на сервер. Сборка под МиниГуи. Задание вручную параметров размера буфера транзакций.
| |
|
|
| Администратор
|
Пост N: 3276
Зарегистрирован: 23.05.05
|
|
Отправлено: 07.06.15 13:35. Заголовок: nbatocanin пишет: Э..
nbatocanin пишет: цитата: | Эта программа работает 73 секунд. Без Begin/EndTransaction работает 15 секунд. Почему это так, и может ли это быть ускорено? Спасибо, Ненад |
| Если транзакция большая, то желательно задать параметр для Leto_BeginTransaction([ nBlockLen ]) Это размер памяти в байтах для выделения и перевыделения памяти. Попробуйте задать этот параметр равным 16k, или больше Можно разбить большую транзакцию на несколько маленьких, по количеству добавляемых записей.
| |
|
|
| |
Пост N: 2
Зарегистрирован: 10.01.15
|
|
Отправлено: 08.06.15 14:38. Заголовок: leto_directory
Почему leto_directory бы не вернуться имена каталога на сервере LetoDB? У меня есть 3 каталоги на сервере LetoDB но пример вернуться только один файл (test2.txt) #include "rddleto.ch" Function Main( cPath ) Local lRes, cBuf, arr, i REQUEST LETO RDDSETDEFAULT( "LETO" ) IF Empty( cPath ) cPath := "//127.0.0.1:2812/" ELSE cPath := "//" + cPath + Iif( Right(cPath,1) $ "/\", "", "/" ) ENDIF ? "Connect to " + cPath + " - " IF ( leto_Connect( cPath ) ) == -1 nRes := leto_Connect_Err() IF nRes == LETO_ERR_LOGIN ?? "Login failed" ELSEIF nRes == LETO_ERR_RECV ?? "Recv Error" ELSEIF nRes == LETO_ERR_SEND ?? "Send Error" ELSE ?? "No connection" ENDIF Return Nil ELSE ?? "Ok" ENDIF ? ? 'leto_file( "test1.txt" ) - ' ?? Iif( leto_file( cPath + "test1.txt" ), "Ok", "No" ) ? 'leto_memowrite( "test1.txt", "A test N1" ) - ' ?? Iif( leto_memowrite( cPath + "test1.txt", "A test N1" ), "Ok", "Failure" ) ? 'leto_file( "test1.txt" ) - ' ?? Iif( leto_file( cPath + "test1.txt" ), "Ok", "No" ) ? 'leto_memoread( "test1.txt" ) - ' ?? leto_memoread( cPath + "test1.txt" ) ? 'leto_frename( "test1.txt","test2.txt" ) - ' ?? Iif( leto_frename( cPath + "test1.txt","test2.txt" ) == 0, "Ok", "Failure" ) ? 'leto_file( "test1.txt" ) - ' ?? Iif( leto_file( cPath + "test1.txt" ), "Ok", "No" ) ? 'leto_file( "test2.txt" ) - ' ?? Iif( leto_file( cPath + "test2.txt" ), "Ok", "No" ) ? 'leto_fileread( "test2.txt", 7, 2 ) - ' ?? Iif( leto_fileread( cPath + "test2.txt", 7, 2, @cBuf ) > 0, cBuf, "Failure" ) ? 'leto_filewrite( "test2.txt", 7, "N2" ) - ' ?? Iif( leto_filewrite( cPath + "test2.txt", 7, "N2" ), "Ok", "Failure" ) ? 'leto_memoread( "test2.txt" ) - ' ?? leto_memoread( cPath + "test2.txt" ) ? 'leto_filesize( "test2.txt" ) - ' ?? leto_filesize( cPath + "test2.txt" ) arr := leto_directory( cPath ) ? 'leto_directory(): (' + Ltrim(Str(Len(arr))) + ")" ? "Press any key to continue..." Inkey(0) FOR i := 1 TO Len( arr ) ? arr[i,1] NEXT ? "----------" ? 'leto_ferase( "test2.txt" ) - ' ?? Iif( leto_fErase( cPath + "test2.txt" ) == 0, "Ok", "Failure" ) ? ? "Press any key to finish..." Inkey(0) Return Nil
| |
|
|
| Администратор
|
Пост N: 3277
Зарегистрирован: 23.05.05
|
|
Отправлено: 08.06.15 15:14. Заголовок: Добавьте при вызове ..
Добавьте при вызове функции 2-й параметр: arr := leto_directory( cPath, "D" ) и массив arr будет включать и имена каталогов.
| |
|
|
| |
Пост N: 3
Зарегистрирован: 10.01.15
|
|
Отправлено: 08.06.15 19:31. Заголовок: спасибо! но опять не..
спасибо! но опять некоторое время возвращает пустую строку, когда вы запустите программу снова это хорошо
| |
|
|
| Администратор
|
Пост N: 3279
Зарегистрирован: 23.05.05
|
|
Отправлено: 09.06.15 07:55. Заголовок: Дайте пожалуйста при..
Дайте пожалуйста пример
| |
|
|
| |
Пост N: 21
Зарегистрирован: 06.05.14
|
|
Отправлено: 12.06.15 17:46. Заголовок: Pasha пишет: Pasha..
Pasha пишет: [quote]` Pasha пишет: цитата: | Если транзакция большая, то желательно задать параметр для Leto_BeginTransaction([ nBlockLen ]) Это размер памяти в байтах для выделения и перевыделения памяти. Попробуйте задать этот параметр равным 16k, или больше Можно разбить большую транзакцию на несколько маленьких, по количеству добавляемых записей. |
| Извините за задержку. Я пытался изменить этот параметр, и получил небольшое улучшение (69 секунд). Менся здесь действительно не нужно транзакции, я просто хочу, чтобы ускорить группа REPLACE команды. Я думал, что транзакции это сделать.
| |
|
|
| |
Пост N: 22
Зарегистрирован: 06.05.14
|
|
Отправлено: 12.06.15 18:26. Заголовок: Andrey пишет: Попро..
Andrey пишет: цитата: | Попробуйте тесты, которые я сделал и проверял. - https://cloud.mail.ru/public/Lr52/WR9soGyFn TEST_DBF.hbp - терминалка сделанная SergKis. Закачивает базу на сервер супер быстро. Сборка под МиниГуи для терминалки. DbftoServer.hbp - загрузка dbf на сервер. Сборка под МиниГуи. Задание вручную параметров размера буфера транзакций. |
| Очень интересные и полезные примеры! Спасибо!
| |
|
Ответов - 191
, стр:
1
2
3
4
5
6
7
8
9
10
All
[только новые]
|
|
|