Локальные сети персональных компьютеров. Работа с сервером Novell NetWare© Александр Фролов, Григорий ФроловТом 9, М.: Диалог-МИФИ, 1993, 168 стр. 5.2. Блокирование физических записейЕсли вы разрабатываете СУБД с коллективным доступом к файлам базы данных, расположенным на сервере, метод блокирования файлов может оказаться не слишком удобным. Так как разные пользователи в разные моменты времени работают с различными участками (записями) базы данных, едва ли стоит блокировать весь файл, если один из пользователей решил изменить содержимое только одной записи в базе данных. Было бы лучше заблокировать только эту запись. Средства сетевой оболочки позволяют вам блокировать отдельные записи в разных файлах, образуя группу блокируемых записей (по аналогии с группой файлов, рассмотренной нами в предыдущем разделе). В группу могут входить записи из одного или нескольких файлов. Каждая запись идентифицируется индексом файла (файл необходимо открыть функцией open() или аналогичными средствами), смещением начала записи в байтах от начала файла и размером записи в байтах. Для создания группы физических записей используется функция LogPhysicalRecord(), аналогичная по назначению функции LogFile(), но работающая с записями. Удалить запись из группы можно функцией ClearPhysicalRecord(). Вся группа записей удаляется функцией ClearPhysicalRecordSet(). Записи можно блокировать сразу при их добавлении в группу либо позже. Вы можете заблокировать сразу все записи, относящиеся к группе, вызвав функцию LockPhysicalRecordSet(). Для разблокирования записи используется функция ReleasePhysicalRecord(). Если надо разблокировать сразу все записи, вызывайте функцию ReleasePhysicalRecordSet(). Функция LogPhysicalRecord() имеет следующий прототип: int LogPhysicalRecord(int FileHandle, long RecordStartOffset, long RecordLength, BYTE LockDirective,WORD Timeout); Параметр FileHandle задает индекс файла, которому принадлежит блокируемая запись. Параметры RecordStartOffset и RecordLength задают смещение от начала файла и размер блокируемой записи в байтах. Параметр LockDirective определяет, надо ли блокировать запись сразу после его добавления в группу:
Параметр Timeout определяет период времени (в 18-х долях секунды), в течение которого файл-сервер будет ожидать, если запись нельзя заблокировать немедленно. Если для этого параметра задать нулевое значение, ожидание выполняться не будет. Функция возвращает 0 при успешном завершении или код ошибки:
Для удаления записи из группы можно использовать функцию ClearPhysicalRecord(): int ClearPhysicalRecord(int FileHandle, long RecordStartOffset, long RecordLength); Параметры этой функции аналогичны параметрам функции LogPhysicalRecord. Функция возвращает нулевое значение или значение 0xFF, если в списке нет указанной записи. Функция ClearPhysicalRecordSet() позволяет разблокировать все записи группы и удалить группу void ClearPhysicalRecordSet(void); Прототип функции LockPhysicalRecordSet(), используемой для блокирования группы записей: int LockPhysicalRecordSet(BYTE LockDirective, WORD Timeout); Параметр LockDirective задает режим блокирования. Если он равен 0, записи блокируются для монопольного использования программой, заблокировавшей записи. Если параметр имеет значение 1, записи блокируются для совместного использования в режиме чтения. Параметр Timeout используется так же, как и при вызове функции LogPhysicalRecord(). Функция возвращает 0 при успешном завершении или код ошибки:
После того как группа записей заблокирована, вы можете разблокировать отдельные записи или всю группу сразу. Для разблокирования отдельных записей используйте функцию ReleasePhysicalRecord(): int ReleasePhysicalRecord(int FileHandle, long RecordStartOffset, long RecordLength); Параметры задают индекс файла, смещение записи и ее длину. Функция возвращает нулевое значение или значение 0xFF, если указанной записи нет в списке. Если надо разблокировать сразу все записи, добавленные в группу, используйте функцию ReleasePhysicalRecordSet(): void ReleasePhysicalRecordSet(void); Для добавления записей в группу вместо функции LogPhysicalRecord() можно использовать функцию BCh прерывания INT 21h:
Для удаления записи из списка вместо функции ClearPhysicalRecord() можно использовать функцию BEh прерывания INT 21h:
Для удаления группы записей и разблокирования всех записей вместо функции ClearPhysicalRecordSet() можно использовать функцию C4h прерывания INT 21h:
Для блокирования группы записей вместо функции LockPhysicalRecordSet() можно использовать функцию C2h прерывания INT 21h:
Для разблокирования записи вместо функции ReleasePhysicalRecord() можно использовать функцию BDh прерывания INT 21h:
Для разблокирования группы записей вместо функции ReleasePhysicalRecordSet() можно использовать функцию C3h прерывания INT 21h:
5.2.1. Программа PHYSLOCKДля иллюстрации блокирования физических записей файла мы составили две программы - PHYSLOCK (листинг 22) и RECACC (листинг 23). Первая программа вводит с консоли имена файлов, смещения и размеры записей. Все введенные файлы открываются, так как для добавления записей нужен индекс файлов. Затем записи блокируются функцией LockPhysicalRecordSet(), после чего программа переходит в состояние ожидания и находится в нем до тех пор, пока оператор не нажмет любую клавишу. В это время записи заблокированы. С помощью программы RECACC вы можете попытаться выполнить запись в заблокированные или свободные записи. Когда оператор нажмет клавишу, программа PHYSLOCK разблокирует все записи и удалит набор записей. // =================================================== // Листинг 22. Блокирование физических записей файлов // Файл physlock\physlock.cpp // // (C) A. Frolov, 1993 // =================================================== #include <stdlib.h> #include <stdio.h> #include <string.h> #include <conio.h> #include <fcntl.h> #include <io.h> #include <sys\stat.h> #include <share.h> #define BYTE unsigned char #define WORD unsigned int extern "C" int GetNetWareShellVersion(char *,char *, char *); extern "C" int LogPhysicalRecord(int, long, long, BYTE, WORD); extern "C" int LockPhysicalRecordSet(BYTE, WORD); extern "C" void ReleasePhysicalRecordSet(void); extern "C" void ClearPhysicalRecordSet(void); void main(void) { char MajorVersion=0; char MinorVersion=0; char Revision=0; char FilePath[255]; int FileHandle; char Buff[80]; long RecordStartOffset; long RecordLength; int ccode; printf("\n*PHYSLOCK* (C) Frolov A., 1993\n"); // Проверяем наличие сетевой оболочки asm push si GetNetWareShellVersion(&MajorVersion, &MinorVersion, &Revision); asm pop si if(MajorVersion == 0) { printf("\nОболочка NetWare не загружена\n"); return; } // Создаем набор записей файлов, которые будут заблокированы for(;;) { printf("\nВведите путь к файлу или '-':"); gets(FilePath); strupr(FilePath); if(FilePath[0] == '-') break; // Открываем файл, в котором мы будем блокировать физические записи if ((FileHandle = open(FilePath, O_RDWR | O_BINARY | O_DENYNONE, SH_DENYNONE)) == -1) { printf("Не могу открыть файл\n"); continue; } // Задаем начало и размер блокируемой области файла printf("\nВведите смещение начала записи:"); gets(Buff); RecordStartOffset = atol(Buff); printf("\nВведите размер записи:"); gets(Buff); RecordLength = atol(Buff); // Добавляем запись в набор ccode = LogPhysicalRecord(FileHandle, RecordStartOffset, RecordLength, 0, 0); if(!ccode) printf("Файл %s добавлен к списку\n", FilePath); else printf("Ошибка при добавлении %02.2X\n", ccode); } // Блокируем набор файлов ccode = LockPhysicalRecordSet(0, 0); if(!ccode) printf("Записи файлов заблокированы\n"); else printf("Ошибка при блокировании " "записей файлов %02.2X\n", ccode); printf("Для разблокирования записей " "файлов нажмите любую клавишу\n"); getch(); // Разблокируем набор файлов ReleasePhysicalRecordSet(); // Удаляем набор файлов ClearPhysicalRecordSet(); // Закрываем файл close(FileHandle); } 5.2.2. Программа RECACCПрограмма RECACC (листинг 23) предназначена для работы вместе с программой PHYSLOCK. Она запрашивает с консоли путь к файлу, а также смещение области памяти, в которую затем будет записана небольшая текстовая строка. Если эта область окажется заблокированной, программа завершается сообщением об ошибке. // =================================================== // Листинг 23. Проверка возможности получения // доступа к физическим записям файла // Файл recacc\recacc.cpp // // (C) A. Frolov, 1993 // =================================================== #include <stdlib.h> #include <stdio.h> #include <string.h> #include <conio.h> #include <fcntl.h> #include <io.h> #include <dos.h> #include <sys\stat.h> #include <share.h> #define BYTE unsigned char #define WORD unsigned int extern "C" int LogPhysicalRecord(int, long, long, BYTE, WORD); extern "C" int LockPhysicalRecordSet(BYTE, WORD); extern "C" void ReleasePhysicalRecordSet(void); extern "C" void ClearPhysicalRecordSet(void); void main(void) { char FilePath[255]; int FileHandle; char Buff[80]; long RecordStartOffset; char msg[] = "PATCH!!!"; int ccode; unsigned count; printf("\n*RECACC* (C) Frolov A., 1993\n"); // Вводим имя файла и открываем его на запись и чтение printf("\nВведите путь к файлу:"); gets(FilePath); strupr(FilePath); if ((FileHandle = open(FilePath, O_RDWR | O_BINARY | O_DENYNONE, SH_DENYNONE)) == -1) { printf("Не могу открыть файл\n"); } // Задаем смещение в файле, начиная с которого // в файл будет записана строка "PATCH!!!" printf("\nВведите смещение начала записи:"); gets(Buff); RecordStartOffset = atol(Buff); // Позиционируем на начало записи lseek(FileHandle, RecordStartOffset, 0); // Делаем попытку изменить содержимое записи ccode = _dos_write(FileHandle, msg, strlen(msg), &count); if(!ccode) printf("Запись обновлена\n"); else printf("Ошибка при обновлении " "записи в файле: %02.2X\n", ccode); // Закрываем файл close(FileHandle); } |