Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Локальные сети персональных компьютеров. Работа с сервером 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 определяет, надо ли блокировать запись сразу после его добавления в группу:

0x00 Запись добавляется в группу, но не блокируется
0x01 Добавляемая запись блокируется для использования заблокировавшей его программой в монопольном режиме
0x03 Добавляемая запись блокируется для совместного использования

Параметр Timeout определяет период времени (в 18-х долях секунды), в течение которого файл-сервер будет ожидать, если запись нельзя заблокировать немедленно. Если для этого параметра задать нулевое значение, ожидание выполняться не будет.

Функция возвращает 0 при успешном завершении или код ошибки:

Код ошибки Значение
0x96 Мало памяти на файл-сервере
0xFE Истек период ожидания, заданный параметром Timeout, но запись так и не удалось заблокировать
0xFF Сбой при блокировании записи

Для удаления записи из группы можно использовать функцию 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 при успешном завершении или код ошибки:

Код ошибки Значение
0xFE Истек период ожидания, заданный параметром Timeout, но запись так и не удалось заблокировать
0xFF Сбой при блокировании записи

После того как группа записей заблокирована, вы можете разблокировать отдельные записи или всю группу сразу.

Для разблокирования отдельных записей используйте функцию ReleasePhysicalRecord():

int ReleasePhysicalRecord(int FileHandle,
    long RecordStartOffset, long RecordLength);


Параметры задают индекс файла, смещение записи и ее длину. Функция возвращает нулевое значение или значение 0xFF, если указанной записи нет в списке.

Если надо разблокировать сразу все записи, добавленные в группу, используйте функцию ReleasePhysicalRecordSet():

void  ReleasePhysicalRecordSet(void);


Для добавления записей в группу вместо функции LogPhysicalRecord() можно использовать функцию BCh прерывания INT 21h:

На входе: AH = BCh;
AL = Параметр LockDirective;
BP = Параметр Timeout;
BX = Индекс файла;
CX = Старшее слово смещения записи относительно начала файла;
DX = Младшее слово смещения;
SI = Длина записи.
На выходе: AL = Код ошибки или 0, если операция завершилась без ошибок.

Для удаления записи из списка вместо функции ClearPhysicalRecord() можно использовать функцию BEh прерывания INT 21h:

На входе: AH = BEh;
BX = Индекс файла;
CX = Старшее слово смещения записи относительно начала файла;
DX = Младшее слово смещения.
На выходе: AL = Код ошибки или 0, если операция завершилась без ошибок.

Для удаления группы записей и разблокирования всех записей вместо функции ClearPhysicalRecordSet() можно использовать функцию C4h прерывания INT 21h:

На входе: AH = C4h.
На выходе: AL = Код ошибки или 0, если операция завершилась без ошибок.

Для блокирования группы записей вместо функции LockPhysicalRecordSet() можно использовать функцию C2h прерывания INT 21h:

На входе: AH = C2h;
AL = Параметр LockDirective;
BP = Параметр Timeout.
На выходе: AL = Код ошибки или 0, если операция завершилась без ошибок.

Для разблокирования записи вместо функции ReleasePhysicalRecord() можно использовать функцию BDh прерывания INT 21h:

На входе: AH = BDh;
BX = Индекс файла;
CX = Старшее слово смещения записи относительно начала файла;
DX = Младшее слово смещения.
На выходе: AL = Код ошибки или 0, если операция завершилась без ошибок.

Для разблокирования группы записей вместо функции ReleasePhysicalRecordSet() можно использовать функцию C3h прерывания INT 21h:

На входе: AH = C3h.
На выходе: = Регистры не используются.

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);
}


[Назад] [Содеожание] [Дальше]