On-line: Andrey, гостей 3. Всего: 4 [подробнее..]
АвторСообщение
постоянный участник


Пост N: 1362
Зарегистрирован: 27.01.07
ссылка на сообщение  Отправлено: 21.01.18 10:31. Заголовок: LetoDb fork


https://github.com/elchs/LetoDBf
https://github.com/elchs/LetoDBf/blob/master/README.md
Кто-нибудь пробовал или использует в продакшене?

Спасибо: 0 
ПрофильЦитата Ответить
Ответов - 125 , стр: 1 2 3 4 5 6 7 All [только новые]


постоянный участник


Пост N: 1363
Зарегистрирован: 27.01.07
ссылка на сообщение  Отправлено: 21.01.18 16:08. Заголовок: Попробовал. Наткнулс..


Попробовал. Наткнулся на вылет OrdKeyNo(), которого не было с "оригинальным" LetoDB. На этом эксперименты пока закончены)

Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 575
Зарегистрирован: 08.07.06
ссылка на сообщение  Отправлено: 09.02.18 01:04. Заголовок: Использую, доволен. ..


Использую, доволен. Оригинальную ("нашу") версию не юзал, начал сразу с форка.

Был момент, когда Rolf (elch) пропал куда-то из эфира и стало немного ссыкотно. Сейчас вроде активничает.

Если есть что обсудить - welcome.

Спасибо: 0 
ПрофильЦитата Ответить
администратор




Пост N: 6718
Зарегистрирован: 17.05.05
ссылка на сообщение  Отправлено: 09.02.18 14:14. Заголовок: Sergy пишет: Ориги..


Sergy пишет:

 цитата:
Оригинальную ("нашу") версию не юзал, начал сразу с форка.


А что есть какие то полезные плюшки в форке в отличии от нашей ?

Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 576
Зарегистрирован: 08.07.06
ссылка на сообщение  Отправлено: 09.02.18 19:01. Заголовок: Dima пишет: А что е..


Dima пишет:

 цитата:
А что есть какие то полезные плюшки в форке в отличии от нашей ?


На этот вопрос грамотно ответить не смогу, тк плотному знакомству с оригинальным вариантом что то постоянно мешало. Например:

1) необходимость (?) указания для каждой операции адреса коннекта для каждого файла, например: вместо привычного USE tablename ... писать USE (cConnectPath+"tablename") ... Может это и не так на самом деле, но в каждом примере фигурировал примерно такой синтаксис команд. Слишком много кода перелелывать ради не очень понятной перспективы. В форке делается один раз Leto_Connect("191.168.x.x:2812") и всё. Все остальные USE, INDEX, SELECT и тп работают вообще без каких либо модификаций по сравнению с привычным DBFNTX. Единственное что - пришлось кое-где пошаманить с фильтрами, чтобы они фильтровали на сервере, а не на клиенте. Для этого заменяю потихоньку, одно за другим, выражения вроде:

SET FILTER TO (table->date >= d1) .AND. (table->date <= d2)

на

tmp := "(table->date >= 0d" +DTOS(d1)+ ") .AND. (table->date <= 0d" +DTOS(d2)+ ")"
SET FILTER TO &tmp

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

2) Мелочь конечно, но сама идея передавать при каждом вызове Leto_Somefunc(...) неведомую мне UserStru противоречит моим принципам программирования. Если есть некий набор данных, который нужен серверу, а не клиенту - зачем его хранить на клиенте и каждый раз передавать серверу при вызове функции ? Пусть сервер его сам у себя и хранит. Места в памяти и на диске достаточно.

Ну и пара мелочей:

3) Рольф организовал "двухканальный" обмен данными между клиентом и сервером. Т.е. после каждой операции передачи пакета не теряется время на получение сигнала ACK (пакет получен), а сразу передаётся следующий - один за одним. Для обмена сообщениями о некорректном приеме пакетов (NO-ACK) используется второй порт (обычно 2813). И по нему 99,99% времени ничего не передается вообще - тк в большинстве случаев проблем передачи нет как таковых. В случае получения NO-ACK происходит генерация ошибки стандартным способом. Таким образом, вместо миллионов ACK-ACK-ACK..., забивающих канал связи и фрагментирующих пакеты - клиент и сервер изредка (!) кидают NO-ACK по соседнему порту, что должно давать прирост производительности. Я лично не проверял, но почему-то верю ... )))

4) Не знаю, было ли реализовано в оригинале, но Рольф рекомендует после Leto _Connect(...) сразу вызывать Leto_ToggleZip(1) - чтобы включить быстрый алгоритм LZ4 для сжатия пакетов на лету. При копировании обычных dbf дает прирост производительности 20-40%, что само по себе неплохо. Это я проверял лично.

Вот такие мои впечатления за примерно полгода знакомства с "crazy russians db engine, modified with german accuracy..." или что то типа того, как писал Рольф.

Спасибо: 0 
ПрофильЦитата Ответить
постоянный участник




Пост N: 1718
Зарегистрирован: 17.02.12
ссылка на сообщение  Отправлено: 09.02.18 21:07. Заголовок: Sergy пишет Для этог..


Sergy пишет
 цитата:
Для этого заменяю потихоньку, одно за другим, выражения вроде:


это, точно, надо делать ?
в примере test_filt.prg есть
 
PRIVATE nNumTop, nNumBot
...
nNumTop := 1004
nNumBot := 1010
SET FILTER TO NUM >= nNumTop .AND. NUM <= nNumBot
? "with FORCEOPT = .F."
? DbFilter(), "; optimized:", LETO_ISFLTOPTIM()

?
#ifndef __XHARBOUR__ /* -> RTE cause of missing filter sync */
SET( _SET_FORCEOPT, .T. )

#endif
SET FILTER TO NUM >= nNumTop .AND. NUM <= nNumBot
? "with FORCEOPT = .T."
? DbFilter()
? "--> optimized:", LETO_ISFLTOPTIM()
...

readme_rus.txt

 цитата:

функции dbSetFilter(). Фильтр, который может быть выполнен на сервере, называется оптимизированным.
Если фильтр не может быть выполнен на сервере, он является неоптимизированным. Такой фильтр
является медленным, поскольку с сервера все равно запрашиваются все записи, которые затем
фильтруются на клиенте. Чтобы задать оптимизированный фильтр, необходимо, чтобы в логическом
выражении для фильтра отсутствовали переменные или функции, определенные на клиенте.
Чтобы проверить, является ли фильтр оптимизированным, надо вызвать функцию LETO_ISFLTOPTIM().




Спасибо: 0 
ПрофильЦитата Ответить
постоянный участник




Пост N: 1719
Зарегистрирован: 17.02.12
ссылка на сообщение  Отправлено: 09.02.18 21:12. Заголовок: PS. Сори, не туда н..



PS. Сори, не туда нажал.
т.е. в "нашей" версии из за переменных фильтр не оптимизирован, а тут показан, что оптимизирован.

Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 577
Зарегистрирован: 08.07.06
ссылка на сообщение  Отправлено: 09.02.18 22:51. Заголовок: SergKis пишет: т.е...


SergKis пишет:

 цитата:
т.е. в "нашей" версии из за переменных фильтр не оптимизирован, а тут показан, что оптимизирован.



Не очень понял про отличия "нашей" и "форк" версии в отношении оптимизированных фильтров, но компиляция и запуск test_filt.prg выдает следующее:

Testing filtering for DBFCDX                   

ordSetFocus( "NAME" )
seek 1001 Petr 09/02/18 - Ok
seek 1010 Andrey 18/02/18 - Ok

NUM >= 1004 .AND. NUM <= 1010 ; optimized: .F.
go top 1005 Alexey 13/02/18 - Ok
go bottom 1008 Vladimir 16/02/18 - Ok
seek 0 / / - Ok
seek 1010 Andrey 18/02/18 - Ok

with FORCEOPT = .F.
NUM >= nNumTop .AND. NUM <= nNumBot ; optimized: .F.

with FORCEOPT = .T.
NUM >= nNumTop .AND. NUM <= nNumBot
--> optimized: .F.
go top 1005 Alexey 13/02/18 - Ok
go bottom 1008 Vladimir 16/02/18 - Ok
seek 0 / / - Ok
seek 1010 Andrey 18/02/18 - Ok


cName $ NAME ; 'Alex' $ NAME - optimized: .F.
go top 1003 Alexander 11/02/18 - Ok
go bottom 1005 Alexey 13/02/18 - Ok
seek 0 / / - Ok
count 42 - Ok




Спасибо: 0 
ПрофильЦитата Ответить
постоянный участник




Пост N: 1720
Зарегистрирован: 17.02.12
ссылка на сообщение  Отправлено: 09.02.18 23:14. Заголовок: Sergy пишет выдает с..


Sergy пишет
 цитата:
выдает следующее


Ясненько.
Я см. только по тексту примера, нет установленного форк, из него понял, как понял

Увидел, прицепленный rdd SIXCDX, что не плохо.
 
leto_DbDriver( [ <cNewDriver> ], [ <cMemoType> ], [ <nBlocksize> ] )
==> aInfo
убрааны
LETO_SETSEEKBUFFER( nRecsInBuf ) ==> 0
! DEPRECATED !

LETO_SETFASTAPPEND( lFastAppend ) ==> .F.
! DEPRECATED !
не использовал.

Leto_FCopyToSrv( cLocalFileName, sServerFileName[, nStepSize ] )
==> lSuccess
Leto_FCopyFromSrv( cLocalFileName, sServerFileName[, nStepSize ] )
==> lSuccess
Copy a file from/ to client to/ from server, where:
инересненько

с переменными PUBLIC\PRIVATE пробовал ?
cExpr := Leto_VarExprCreate( "Memvar1 [, MemvarX ]", @aArr )
Repeatedly call after each occasion of changed value:
Leto_VarExprSync( aArr )
Clean up with:
Leto_VarExprClear( aArr )

LETO_VAREXPRTEST( cExpression ) ==> lContainMemvar

Return TRUE ( .T. ) if <cExpression> contains memvars

LETO_VAREXPRCREATE( cExpression [, @aLetoVar ] ) ==> cModifiedExpression
...

если объявленное в readme.txt работает, то есть движение вперед

Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 578
Зарегистрирован: 08.07.06
ссылка на сообщение  Отправлено: 10.02.18 00:01. Заголовок: До серверных процеду..


До серверных процедур (RPC, UDF) и обмена переменными пока не дошел.

Пока изучаю возможности фонового взаимодействия с LetoDB сервером в отдельных потоках.

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

SET FILTER TO table->client $ hListSelectedClients

Работает шустро, удобно и понятно: в хэш можно выбрать хоть одного клиента, хоть сотню - на производительности это почти никак не скажется. ASCAN() по массиву выбранных клиентов тормозит: чем больше клиентов, тем сильнее.

Сам бы подкинул Рольфу идею, но похоже, что я ему уже мозг вынес и он поставил меня в игнор...

Спасибо: 0 
ПрофильЦитата Ответить
постоянный участник




Пост N: 1721
Зарегистрирован: 17.02.12
ссылка на сообщение  Отправлено: 10.02.18 02:40. Заголовок: Sergy пишет что прин..


Sergy пишет
 цитата:
что принципиально мешает передавать от клиента на сервер массивы и хэши


массивы передаются, как параметры в UDF функции и возврат обратно. массив в hash в udf получить просто,
т.е. исп. вместо set filter ... udf функцию для уст.\снятия фильтра с hash.
еще вариант, можно исп.
leto_SetEnv( xScope, xScopeBottom, xOrder, cFilter, lDeleted )
aRecNo := leto_dbEval()
leto_ClearEnv( xScope, xScopeBottom, xOrder, cFilter )
в "нашей" версии aRecNo положить в SkipBufer и обработать записи
DO WHILE ! eof()
...
SKIP
ENDDO
в "форк" не знаю, можно ли так делать ?


Спасибо: 0 
ПрофильЦитата Ответить
постоянный участник




Пост N: 1722
Зарегистрирован: 17.02.12
ссылка на сообщение  Отправлено: 10.02.18 11:36. Заголовок: посмотрел "форк&..


посмотрел "форк" на наличие HB_FUNC
 
LETO_PARSEREC( cRecBuf ) --> nil
LETO_PARSERECODRS( cRecBuf ) --> nil
не увидел, не есть хорошо
режим работы
* UDF_dbEval function returns buffer with records by order <xOrder>, and for condition,
* defined in <xScope>, <xScopeBottom>, <cFilter>, <lDeleted> parameters
* Function call from client:

leto_ParseRecords( leto_Udf('UDF_dbEval', <xScope>, <xScopeBottom>, <xOrder>, <cFilter>, <lDeleted> ) )
while ! eof()
...
skip
enddo
dbInfo( DBI_CLEARBUFFER )

удобен



Спасибо: 0 
ПрофильЦитата Ответить
постоянный участник




Пост N: 1723
Зарегистрирован: 17.02.12
ссылка на сообщение  Отправлено: 10.02.18 11:52. Заголовок: Sergy пишет у меня м..


Sergy пишет
 цитата:
у меня много таких вот конструкций:
SET FILTER TO table->client $ hListSelectedClients


можно заменить на
cKli := ','
while !eof()
cKli += alltrim(table->client)+','
skip
end
потом
SET FILTER TO &( ','+table->client+',' $ '"'+cKli+'"' )


Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 579
Зарегистрирован: 08.07.06
ссылка на сообщение  Отправлено: 10.02.18 13:57. Заголовок: SergKis пишет: масс..


SergKis пишет:

 цитата:
массивы передаются, как параметры в UDF функции и возврат обратно. массив в hash в udf получить просто,
т.е. исп. вместо set filter ... udf функцию для уст.\снятия фильтра с hash.
еще вариант, можно исп.
leto_SetEnv( xScope, xScopeBottom, xOrder, cFilter, lDeleted )
aRecNo := leto_dbEval()
leto_ClearEnv( xScope, xScopeBottom, xOrder, cFilter )
в "нашей" версии aRecNo положить в SkipBufer и обработать записи
DO WHILE ! eof()
...
SKIP
ENDDO
в "форк" не знаю, можно ли так делать ?


Больше 20 лет занимаюсь Clipper/Harbour - но честно говоря, почти ничего не понял из вышесказанного, сорри

Что за SkipBuffer и зачем в него класть aRecNo ?

Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 580
Зарегистрирован: 08.07.06
ссылка на сообщение  Отправлено: 10.02.18 13:59. Заголовок: SergKis пишет: пос..


SergKis пишет:

 цитата:

посмотрел "форк" на наличие HB_FUNC

LETO_PARSEREC( cRecBuf ) --> nil
LETO_PARSERECODRS( cRecBuf ) --> nil
не увидел, не есть хорошо
режим работы
  * UDF_dbEval function returns buffer with records by order <xOrder>, and for condition,  
* defined in <xScope>, <xScopeBottom>, <cFilter>, <lDeleted> parameters
* Function call from client:

leto_ParseRecords( leto_Udf('UDF_dbEval', <xScope>, <xScopeBottom>, <xOrder>, <cFilter>, <lDeleted> ) )
while ! eof()
...
skip
enddo
dbInfo( DBI_CLEARBUFFER )



удобен
Не пользовался, но в readme.txt есть пометка:

see new LETO_DBEVAL() as powerful alternative, or sample of UDF_dbEval() in tests/letoudf.prg

Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 581
Зарегистрирован: 08.07.06
ссылка на сообщение  Отправлено: 10.02.18 14:00. Заголовок: SergKis пишет: можн..


SergKis пишет:

 цитата:
можно заменить на
cKli := ','
while !eof()
cKli += alltrim(table->client)+','
skip
end
потом
SET FILTER TO &( ','+table->client+',' $ '"'+cKli+'"' )



В паре мест делаю примерно похожим образом, но это 'костыли': чем длиннее строка, тем медленнее она будет обрабатываться. Хотелось-бы нормальное решение.

Спасибо: 0 
ПрофильЦитата Ответить
администратор




Пост N: 6719
Зарегистрирован: 17.05.05
ссылка на сообщение  Отправлено: 10.02.18 14:27. Заголовок: Sergy пишет: Хотело..


Sergy пишет:

 цитата:
Хотелось-бы нормальное решение.


В Leto Павел делал BM фильтры , не подходит ?

Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 582
Зарегистрирован: 08.07.06
ссылка на сообщение  Отправлено: 10.02.18 15:41. Заголовок: Dima пишет: В Leto ..


Dima пишет:

 цитата:
В Leto Павел делал BM фильтры , не подходит ?


Поддержка rushmore bitmap фильтров в форке никуда не делась и для многократной выборки - вполне: сначала выбрать нужные записи, потом уже по ним работать. Например в DbEdit().

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

Спасибо: 0 
ПрофильЦитата Ответить
постоянный участник




Пост N: 1724
Зарегистрирован: 17.02.12
ссылка на сообщение  Отправлено: 10.02.18 17:43. Заголовок: Sergy пишетпочти нич..


Sergy пишет
 цитата:
почти ничего не понял из вышесказанного


Leto сервер может подключать hrb файл с пользовательскими функциями при наличии оного.
Пример letoudf.hrb, получаемый из letoudf.prg. Функции вызываются с клиента, исполняются на сервере.
Им могут передаваться параметры типов: C,N,L,D,A, которые можно применять на сервере.
В "нашей" версии первым в функцию передается nUserStru. Условно можно назвать номером соединения со стороны
сервера с клиентом. Кроме получения данных соединения, nUserStru можно исп. как префикс файлов (подкаталог)
для получаемых на сервере файлов выборок и возврата на клиента списка имен файлов, для открытия и дальнейшего
исп. на клиенте, с удалением после работы. То, что в "форк" убран nUserStru, не уверен что это хорошо, надо посмотреть.

В "форк" LETO_DBEVAL( [ <cBlock> ], [ <cFor> ], [ <cWhile> ], [ nNext ], [ nRecord ], [ lRest ] ) ==> aResults
возвращает массив RecNo для исп. в BM фильтрах или собственными dbGoto(...)
В "нашей" версии кроме BM фильтров и dbGoto(...) есть механизм на сервере заполнения SkipBuffer (это буфер
для nn записей), исп. при работе leto серверов (можно уст. кол-во строк в буфере есть ф-я). По этому буферу
идет работа на клиенте dbSkip() и т.д.. Формируем SkipBuffer выполнением ф-ии на сервере
leto_ParseRecords( leto_Udf('UDF_dbEval', <xScope>, <xScopeBottom>, <xOrder>, <cFilter>, <lDeleted> ) )
на входе leto_ParseRecords строка. Получается аналог SET FILTER TO ..., т.е. минимум изм. кода старой проги. Далее работа в цикле.
В "форк" отсутствие leto_ParseRecords, по мну, БАААЛЬШОЙ минус, не смертельный, но ...



Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 583
Зарегистрирован: 08.07.06
ссылка на сообщение  Отправлено: 11.02.18 01:46. Заголовок: Более-менее понятно,..


Более-менее понятно, но очень уж зависимо от конкретной реализации. Пытаюсь по максимуму использовать стандартизованный интерфейс харборовских RDD и не использовать без особой необходимости Leto_xxx(). Ведь если через пару-тройку лет появится какой-нибудь WinterDB - опять всё переписывать?

У меня половина юзеров работает с базой удаленно, через RDP. Для них - данные локальны и выборка идет через dbfntx. Другя половина - как обычно, через сеть. Сначала полностью через dbfntx, сейчас - без особой спешки все больше и больше операций переключаю на LetoDBf.

Форк интересен (для меня) тем, что открыв таблицу один раз VIA "dbfntx" (rdp-локально) или VIA "leto" (по сети) я больше ничего не модифицирую в коде. Максимум - оптимизирую фильтр для выполнения на сервере. Но он точно так же будет работать как с leto, так и с dbfntx.

Пока оставил на "сладкое" некоторые моменты в программе, которые нельзя решить "влоб": как например, не могу отказаться от простого фильтра по хэшу или фильтра, реагирующего на нажатия кнопок на клавиатуре (живой поиск), например:

SET FILTER TO MyFilter()

Да, сделав специфические заточки под Leto, я потеряю совместимость с dbfntx. Пока непонятно - будет ли стоить овчинка выделки. Проект большой и раскорячить его мне не хотелось бы. В данный момент у меня даже сетевые юзеры при отсутствии коннекта с LetoDB получат сообщение при входе, но продолжат работать, как ни в чем ни бывало. Чуть медленнее, чем "обычно" (к которому они уже привыкли), но работать.

Понятно, что и локальных rdp-юзеров можно переключить полностью на локальный Leto сервер. И более того - с точки зрения целостности данных так и сделаю. Но процесс перевода небыстр, а для юзеров нужны всё новые и новые фичи, а не только ускорение старых.

Такие вот мысли...

Спасибо: 0 
ПрофильЦитата Ответить
постоянный участник




Пост N: 1725
Зарегистрирован: 17.02.12
ссылка на сообщение  Отправлено: 11.02.18 10:01. Заголовок: Sergy пишет опять вс..


Sergy пишет
 цитата:
опять всё переписывать?


можно исп. обертки функции\классы\препроцессор(leto_file.ch в "форк")
If RddName() == 'LETO'
...
Else
...
EndIf
исп. leto_sum(...), leto_group(...), можно пробнуть адаптировать их под работу без сервера или Пашу попросить это сделать, если очень надо.

 цитата:
Но процесс перевода небыстр, а для юзеров нужны всё новые и новые фичи, а не только ускорение старых.


На новые фичи перейти мне удалось только внедрением letodb с новой организацией базы на cdx (старая ntx), т.е. загрузка на сервер старой и организация переноса изменений (записи таблиц) с новой базы в старую. Новые фичи работают на letodb, старые как было, постепенно старые режимы переключаю на letodb



Спасибо: 0 
ПрофильЦитата Ответить
Ответов - 125 , стр: 1 2 3 4 5 6 7 All [только новые]
Ответ:
1 2 3 4 5 6 7 8 9
большой шрифт малый шрифт надстрочный подстрочный заголовок большой заголовок видео с youtube.com картинка из интернета картинка с компьютера ссылка файл с компьютера русская клавиатура транслитератор  цитата  кавычки моноширинный шрифт моноширинный шрифт горизонтальная линия отступ точка LI бегущая строка оффтопик свернутый текст

показывать это сообщение только модераторам
не делать ссылки активными
Имя, пароль:      зарегистрироваться    
Тему читают:
- участник сейчас на форуме
- участник вне форума
Все даты в формате GMT  3 час. Хитов сегодня: 264
Права: смайлы да, картинки да, шрифты да, голосования нет
аватары да, автозамена ссылок вкл, премодерация откл, правка нет