Скачать исходные тексты с этой статьей в формате MS Word ~60 kB
Наверняка любой программист, пишущий на Visual FoxPro, многопользовательские приложения сталкивался с проблемами падения индексов или порчи DBF файлов на файл сервере.
Используя библиотеку GPLIB MHSOFTWARE http://www.mhsoftware.com/gplib.htm
Можно избежать этих проблем если не теоретически то практически навсегда. Для начала, правда, необходимо установить 32 битового клиента от NOVELL.
Еще необходимо получить http://www.mhsoftware.com/bin/gp30.exe библиотеку. Она имеет статус TRIAL.
У меня установка практически прошла без проблем. Использую я VFP6 + SP4 Window 2000 pro Русский и 32 битовый Novell Client .
После установки выяснилось, в GPLIB нет места для VFP6, возможно в MHSOFTWARE не знали о выходе VFP6 и не добавили в пример обработку Visual FoxPro 6.
Легким движением исправляем эту нелепость в демонстрационном коде:
Смотрите самое начало модуля GPSTART.PRG
DO case CASE version()="Visual FoxPro 03" nFoxVer=3 CASE version()="Visual FoxPro 05" nFoxVer=5 **** Я добавил только эти две строчки CASE version()="Visual FoxPro 06" nFoxVer=5 **** Конец модификации OTHERWISE do form ShowMsg with "FOX_VER" return .f. ENDCASE
Демонстрационный код работает что дальше.
Для защиты своих данных, я использую несколько функций GPLIB.
N_TTSAvail() - Сообщает доступна ли TTS N_TTSBegin() - Начало транзакции N_TTSCommt() - Завершение транзакции N_TTSRollB() - Откат транзакции N_SetAttr( mFile, "+T" ) - Установить флаг TTS на файл N_SetAttr( mFile, "-T" ) - Снять флаг TTS c файла N_FileInfo(mFile) - Получить информацию о файле на файлсервере NetWare
Этого списка функций достаточно, что бы забыть проблемы с падением индексов или таблиц.
Но для грамотного применения необходимы уточнения. К сожалению транзакционный буфер не так велик, как хотелось бы, поэтому приходится делать короткие транзакции.
На файлы необходимо установить флаг TTS.
Представим себе нам необходимо вести базу операций и менять сальдо по счетам. У нас есть база операций TEST и база остатков на счетах SALDOTST. При каждой логической операции нам необходимо добавлять запить в TEST и менять остаток на счете в базе SALDOTST. В реальной жизни одна транзакция может менять гораздо больше количество файлов и добавлять записи в несколько таблиц. Нам необходима целостность данных как логическая так и физическая. Логическая целостность подразумевает списание со счета 1 зачисление на счет 2 и добавление в таблицу TEST записи Физическая целостность, это когда таблицы или CDX не портятся при прерывании записи в них при потере питания или сетевого соединения.
SEEK СЧЕТ-1 Replace OSTATOK with OSTATOK - OUMMAOP SEEK СЧЕТ 2 Replace OSTATOK with OSTATOK + OUMMAOP INSERT INTO TEST from memvar
У нас получилось 3 шага, если представить что между шагом 1 и 2 произошел сбой, что маловероятно, но возможно. Мы получим не корректную информацию. Со счета-1 деньги исчезли, но не появились на счете-2 и не попали в базу операций TEST.
Теперь приведем пример как это избежать, применяя GPLIB.
Function trtest Parameter mTranTyp Private nTransNo,mCod && 0 - одинокая проводка завершаем трнзакцию в модуле && 1 - транзакция не завершена && выходим && - без разблокировки захваченых записей && - без завершения транзакции && удобно применять при массовых транзакциях && следует только убедиться в достаточной длине транзакционного буфера && не рекомендую работать в данном режиме при большом количестве вызовов с параметром 1 && && 2 - завершаем транзакцию && происходит только разблокировка и завершение транзакции && mCod = 0 If mTranTyp <> 2 If mTYPBL = 1 * 1-й вариант If mTranTyp = 0 mLock = flock(mFile) && Блокируем ФАЙЛ на момент транзакции Endif Else * 2-й вариант блокируем только записи с которыми работаем на момент транзакции && В моем случае корректность при поиске гарантируется && Работает значительно быстрее чем 1-й вариант Seek m.LSD If found() If abs(ISS) >= m.SUMMAOP mRECD = alltrim(str(recno())) Else mCod = 1 && Нехватка средств Endif Else Wait window "Не найден "+m.LSD Endif If mCod = 0 Seek m.LSK If found() mRECK = alltrim(str(recno())) Else Wait window "Не найден "+m.LSK Endif mLOCKRECDK = mRECD+","+mRECK If mTranTyp = 0 mLock = rlock( mLOCKRECDK , 'SALDOTST' ) Endif Endif Endif If mCod = 0 If N_TTSAvail() && If mTranTyp = 0 nResult =N_TTSBegin() && Начало транзакции Endif Select SALDOTST Seek m.LSD If found() Replace obd with obd + m.SUMMAOP If TYPLS = 1 && С активного Replace ISS with ISS - m.SUMMAOP Else && С пассивного Replace ISS with ISS - (m.SUMMAOP - m.SUMMAOP - m.SUMMAOP) Endif Replace userop with m.userop Endif Seek m.LSK If found() Replace obk with obk + m.SUMMAOP If TYPLS = 1 && На активный Replace ISS with ISS + m.SUMMAOP Else && На пассивный Replace ISS with ISS + (m.SUMMAOP - m.SUMMAOP - m.SUMMAOP) Endif Replace userop with m.userop Endif && Операцию в базу операций Insert into TEST from memvar If mTranTyp = 0 nResult=N_TTSCommt() && Конец транзакции Endif Else Wait window 'TTS was not available!' Endif If mTranTyp = 0 Unlock all Endif Endif Else nResult=N_TTSCommt() && Get the transaction number Unlock all Endif Return mCod
В примере четко видно, необходимо блокировать записи, которые мы меняем, до того как мы используем TTS.
Если в какой либо момент после объявления транзакции N_TTSBegin() Происходит сбой, зависание сервера, зависание клиента или разрыв сети потеря питания При запуске сервера, при соответствующей настройке NetWare, все незавершенные транзакции откатятся. И таблицы с индексами примут те значения, которые были в них до начала транзакции, на которой произошел сбой. Что собственно и требовалось.
Для работы TTS необходимо установить флаг TTS на те файлы которые вы хотите обрабатывать под эгидой TTS. При этом это не только DBF таблицы но и CDX и FTP и вообще любые файлы, вы же можете использовать транзакционный механизм даже при операциях на низком уровне FOPEN FWRITE FCLOSE. Все же NetWare TTS замечательная штука! К сожалению, в любимой мной операционной системе NT и ее всех клонах нет такой замечательной функции.
Немого хотелось сказать о командах VFP
BEGIN TRANSACTION
END TRANSACTION
ROLLBACK
Эти команды сильно облегчают страдания с падением таблиц и индексов Но TTS NetWare надежней, чем эти встроенные команды. Разумеется, если таблицы расположены на сервере NetWare. С локальными таблицами, проблемы решать придется с менее надежными командами управления транзакциями VISUALFOXPRO.
Короткая работающая программа. GTEST в архиве GTEST.ARJ К данной статье прилагается.
После компиляции и запуска нажмите кнопку СОЗДАТЬ ТЕСТОВУЮ БАЗУ
Проверьте баланс
Запустите ТЕСТ, желательно с нескольких станций.
Во время работы теста попробуйте выключить питание на клиентской машине, или просто выдернуть из сетевой карты кабель, у меня еще была возможность выключать питание на сервере!
Если TTS на NetWare правильно настроен, то при перезагрузке сервера откат транзакций произойдет автоматически. Иначе вашему администратору придется на каждой зависшей транзакции отвечать на утомительные вопросы и что самое страшное, при неверном ответе можно записать в данные те значения которые они имели бы без применения TTS. Поэтому лучше установить флаг
Auto TTS Backout Flag = ON
В файле STARTUP.NCF.
Auto TTS Backout Flag: OFF (задается лишь в STARTUP.NCF)
Описание: авто-отмена TTS при перезагрузке (пропуск подсказок) В AUTOEXEC.NCF на NetWare посмотреть следующие настройки и при необходимости можно их ввести.
set tts abort dump flag = on
Maximum Transactions = 10000
TTS Abort Dump Flag: ON
Описание: включает вывод данных отказанных транзакций в файл регистрации
Maximum Transactions: 10000
Границы: 100 -- 10000
Описание: максимальное число конкурентных транзакций в системе
Зайцев Юрий Владимирович. Заместитель начальника отдела ИПО Новый-Уренгой ф-л "ЗАПСИБКОМБАНК" ОАО ул. 26 съезда КПСС 11 34949 3-14-65 yzh@mail.ru yz@wscb.ru yura@nu.wscb.ru