среда, 17 июля 2013 г.

Ещё один повод отключить Лог.

В одном из предыдущих постов ("Кто такой Auto?") я рекомендовал отключить Лог сервера, в случае не использования. И вот нашёлся ещё один повод. Наблюдая за сообщениями "Process Monitor" (где найти и как настроить см. пост "Lib.ldb") я заметил странную последовательность. Её легко воспроизвести следующим образом. Запускаем "Process Monitor", настраиваем его на PID Z-сервера. Запускаем "Администратор", подключаемся к любой базе, переходим на вкладку "SQL" набираем абракадабру



и выполняем запрос. Ты уже понял, что нам нужно просто сгенерить ошибку. Смотрим "Process Monitor".




Находим длинннннную последовательность обращений к файлу "EServer.log" - "Быстрые" операции запроса информации о файле и такая же "Быстрая" операция записи. То, что обращения происходят "Быстрым" ("Fast") методом это хорошо. Но почему записи идут ПО ОДНОМУ БАЙТУ? Инкремент смещения так же соответствует одному байту (см. выделение). Не иначе как запись сообщения об ошибке идёт по одному байту! А куда спешить? Не надо ошибаться.
Можно взглянуть на стек (на его кусочек; у меня x64, в x32 будет по-другому)




Строки обозначенные "U" - пользовательский режим, "K" - режим ядра. Значить при выводе каждого символа происходит пересечение границы ядра ОС. Но главный вопрос - выполняется ли физический сброс данных на диск при каждой операции ввода-вывода, пока остаётся открытым. Простой инструмент для проверки этого мне не известен, а лезть отладчиком в ядро - занятие не для слабонервных. Да и "игра не стоит свеч". В любом случае пересечение границы ядра ОС при выводе каждого байта "бесценной" информации об ошибке достаточный повод для того, чтобы его просто отключить.
И ещё один главный вопрос - кто виноват? В стеке фигурирует стандартная "Студийная" библиотека времени выполнения msvcrt.dll. По-видимому, это её работа. А если учесть, что в системе может быть установлена произвольная версия этой библиотеки...
Но это уже тема для отдельного поста. Как всегда пиши комментарии (регистрация не требуется) или на почту acbib3@yandex.ru.

четверг, 6 июня 2013 г.

Время жизни


Сколько приходилось сталкиваться с веб-мастерами, у всех одна болезнь - не настраивают время жизни документа. То ли руки не доходят, то ли не знают такую возможность. В результате браузер повторно забирает с сервера статические данные (изображения, стили ...) вместо того, чтобы взять их из локального кэша. Конечно, с распространением скоростных технологий с безлимитным тарифом, актуальность данной настройки снижается. Но так обстоят дела далеко не у всех (у веб-мастеров похоже, что так).
Попробуй объяснить пользователю с мобильником и GPRS, что тебе лень было сделать пару кликов мышью - его дохлое соединение постоянно прокачивает маленькую пиктограмму "/Lib/images/history.gif" размером в полтора килобайта.
Возможно, в результате массового игнорирования данной настройки, браузеры "научились" угадывать валидность по определённым алгоритмам, основанным на косвенной информации. Они ведь должны быть "турбо". Между тем, проблема решается парой кликов в IIS и двумя строчками в Apache. Лучше дать браузеру реальную информацию. Как ты уже понял, эту лёгкую задачу придётся решить и тебе, если ты эксплуатируешь АС-Библиотека-3 с WWW-шлюзом.
Итак, открываем оснастку "Диспетчер служб IIS", проходим по веткам и выделяем папку "Имя компьютера\сайты\Default Web Site\Lib" (виртуальный каталог или приложение WWW-шлюза, если установка не стандартная нужно изменить)



Выбираем элемент "Заголовки ответов" и жмём "Настроить стандартные заголовки ответов..."



,настраиваем параметры


Думаю, здесь всё понятно - через полгода (для примера, реальный срок выбери на основе своих соображений) браузер клиента обновит статические элементы. А они, скорее всего, будут теми же. Хотя кое-что надо бы изменить сразу - поменять логотип ИАНСа на свой, своей библиотеки (ещё ни разу не видел, чтобы кто-то сделал это!!!). Иначе клиенты начинают тупить по поводу - в чей каталог они попали? Просто отредактируй или создай новый файл Help_head.jpg с теми же размерами. После этого, ты вряд ли что-то будешь здесь менять. Конечно, скорее всего браузер выбросит эти файлы из кэша раньше, когда его размер достигнет предела и наши файлы окажутся самыми "старыми".
Настройка повлияет на содержимое заголовков HTTP только для статических файлов. Динамический контент, тот, что генерируется ISAPI расширением Ewww.dll, останется тем же. Проверим это с помощью Fiddler. Вот трассировка загрузки


динамический


статический - таблица стилей (здесь max-age в секундах),


статический - изображение JPEG.

И напоследок одна забавная плюшка. Если в качестве браузера использовать IE любой версии и в настройках "Сервис\Свойства обозревателя\История просмотра\Параметры" указать "Проверять наличие обновления сохранённых страниц: никогда" (чем иногда пользуются некоторые умники вроде меня, для сокращения объёма трафика)


то никогда ничего не будет найдено, даже если оно есть! Проверь сам. Секрет в том, что сайт построен на фреймах и фрейм результата не обновляется. Если его обновить принудительно (только через контекстное меню на пустом поле таблицы результатов поиска), то всё "найдётся". Теоретически это можно исправить - надо перехватить инициативу на сервере и вставить обработчик события, принудительно обновляющий фрейм. Но выглядеть это будет весьма коряво, да и процент пользователей попадающих под данный баг невелик. Думаю, лучше дождаться официального исправления. На этом всё. Как всегда комментируй, или пиши на acbib3@yandex.ru

среда, 10 апреля 2013 г.

Кто такой Auto?


Недавно ко мне обратились с просьбой разобраться с одной непонятной ситуацией. Весьма известному лицу приписывалось авторство, по несвойственной ему теме. Если учесть, что каталог представлен в Интернет, проблема была довольно щекотливой. Поиск в "лог-таблицах" показал, что последним, кто модифицировал эту запись, был некто "Auto". В результате анализа было выявлено интересное свойство "АС-Библиотека-3" при работе со словарём.
Посмотрим, как это работает в "Демо". Создадим три "почти пустых" записи.


Причём первая и третья отличаются, только заглавием. В первой записи свяжем поле 700 (Имя лица - первичная интеллектуальная ответственность) с записью в словаре "ААААА", которую предварительно создадим



(здесь каталогизатор в режиме словаря).


Во второй записи с тем же значением из словаря свяжем поле 600 (Имя лица как предмет).



Третья запись аналогична первой.



Теперь очистим лог-таблицу Demo__Log командой
delete from Demo__Log



и изменим значение поля 700 первой записи с "ААААА" на "БББББ"




перечитаем, используя для поиска поле "Заглавие"="Заглавие" с усечением справа и посмотрим на результат. С первой всё понятно




Во второй записи поле 600а автоматически изменено на "БББББ"




В третьей ещё интересней - 700а изменилось на "БББББ", а 200f осталось "ААААА"



Прочитаем таблицу Demo__Log




вот, тот Auto, который "зловредно" изменяет записи. Кроме того, по крайней мере, в версии 3.3.58 на "Log уровне" "app" (по умолчанию)



, замечена одна особенность - сразу после закрытия окна модификации "Имя лица" и до нажатия кнопки "Сохранить запись" (основную), Z-сервер заваливает лог-файл сообщениями о невозможности модификации записи с DocID=82 (первая запись) так как она блокирована пользователем, то есть мной.




Судя по тексту сообщения - жалуется отдельный индексирующий поток. Он анонимный, поэтому подписывается как Auto.
Есть ли предел и сколько сообщений будет выдано - не знаю, но очень много. Вроде бы в версии 3.3.64 это исправлено, однако это надо проверять.

Теперь соберём всё в кучу:
1. Свойство автоматического обновления сразу всех записей, связанных со словарной записью "Имя лица" весьма полезно при последовательном изменении в связи с появлением или изменением доступной информации о лице. Однако не помешало бы уведомление со стороны программы об изменении не только текущей записи.
2. Следи за "Новичками". Они часто не различают понятия "создать новую запись" и "модифицировать существующую".
3. Если система работает стабильно и ошибок нет - экономь ресурс диска, отключи вывод лога. Поставь в "Параметры сервера" "Log уровень" в "none"

Как всегда - комментируй (регистрация не требуется) или пиши на адрес acbib3@yandex.ru

среда, 16 января 2013 г.

Жмём базу!


Начнём с Access, а закончим MS SQL Express.
Одной из первых серьёзных проблем, с которой пришлось столкнуться - отсутствие 2/3 записей базы. Произошло это сразу после перегона базы из формата АС-2 в АС-3. Поиск по номеру записи показывал присутствие всех, но поиск по автору и другим полям был катастрофическим.
В общем, странность прояснилась сразу после сжатия базы. Оказалось, что процесс индексации (в терминах АС-3) страшным образом потребляет ресурсы базы, она распухает на глазах, и по достижении порога в 2Гб тихо останавливается без всякой ругани. Если ты не знал об этом - возьми на заметку. Знаю, что многие напоролись на этот феномен, и если бы эта инфа была в паблике на тот момент - мне удалось бы сэкономить несколько недель на более полезные дела. Поэтому в скобках приведу несколько фраз исключительно для поисковика (нет половины базы, АС-Библиотека-3 не находит записи, пропали записи в АС-Библиотека-3).
Итак, чем жмём? Естественно Access-ом, скажешь ты. А если для базы выделен отдельный компьютер. Держать на нём офис исключительно для сжатия? А если это выделенный сервер, то даже устанавливать на него офис - есть нонсенс. Существует крайне простая, маленькая и бесплатная утилита под названием JetComp (условия использования на странице продукта и в архиве). Просто вбей название в поисковой строке на сайте Microsoft. Использовать её крайне просто.

В верхней строке указываем базу, а в нижней - имя файла, в котором окажется сжатая база. Я просто копировал путь и добавлял единичку к имени файла. Остальные параметры как есть. После исходный файл удалял, а новый переименовывал. По сравнению со сжатием в Access, здесь есть дополнительный манёвр, на случай нехватки места на разделе диска, можно сжать в файл на другом разделе. Я успешно эксплуатировал эту утилиту в течение двух лет, до перехода на MS SQL.
Если этого мало вот ещё один вариант. Оснастка "Источники данных ODBC" (Панель управления ->Система и безопасность->Администрирование).


Но такая возможность есть не во всех версиях ОС. Например, в моей текущей семёрке нет. Точнее драйвер Jet есть, а доступа через ODBC нет. С другой стороны в предварительном релизе Srv2012 есть

Не будем долго с этим париться. Если есть - грех не воспользоваться. Итак, на вкладке "Пользовательский DSN" жмём кнопку "Добавить...". В появившемся окне выбираем "Microsoft Access Driver (*.mdb)" и жмём "Готово".


В следующем окне появляется заветная кнопка "Сжать...".


Нажимаем и, в диалоге, указываем базу для сжатия.


Нажимаем ОК. В следующем окне указываем имя файла, в который будет сжиматься база. Все, как и в JetComp, но не забудь установить "Формат" в "Версия 4.x".


Жмём ОК и ждём результат.



Далее отменяем всё до кнопки "Сжать..." и жмём следующую базу. После этого закрываем все окна, удаляем старые базы и переименовываем новые. Как видишь, мы ничего не создаём, хотя, исключительно для удобства, можно создать "Пользовательский DSN" и использовать его в качестве ссылки.
Возникает вопрос. Какой метод лучше? С точки зрения собственно сжатия не имеет значения. Раскрою маленький секрет. Функция сжатия реализована в самом движке Jet. И Access и JetComp и ODBC драйвер всего лишь запускают одну и ту же функцию интерфейса IJetCompact, реализованную в движке. Поэтому при выборе средства для сжатия можно ограничиться соображениями удобства.

Теперь SQL. Я коснусь бесплатной версии Express. Его возможностей стало хватать ещё больше после того как в версии 2008 R2 была поднята планка размера б.д. до 10Гб. Платные версии редкий зверь для библиотеки, хотя если задействовать его мощь по полной ...
Собственно функцию сжатия можно запустить в оболочке "SQL Server Management Studio" - это не секрет. Тонкость заключается в предварительной дефрагментации индексов. Следующий скрипт ищет в базе все индексы, с фрагментацией более 10% и обрабатывает. Это не самопал. Скрипт взят из документации Microsoft к SQL Server. При желании найдёшь его там (плюс дополнительная инфа!). Если желания нет - просто скопируй его в студию, установи контекст базы для обработки (см. первый комментарий) и запусти.

-- Ensure a USE <databasename> statement has been executed first.
SET NOCOUNT ON;
DECLARE @objectid int;
DECLARE @indexid int;
DECLARE @partitioncount bigint;
DECLARE @schemaname nvarchar(130); 
DECLARE @objectname nvarchar(130); 
DECLARE @indexname nvarchar(130); 
DECLARE @partitionnum bigint;
DECLARE @partitions bigint;
DECLARE @frag float;
DECLARE @command nvarchar(4000); 
-- Conditionally select tables and indexes from the sys.dm_db_index_physical_stats function 
-- and convert object and index IDs to names.
SELECT
    object_id AS objectid,
    index_id AS indexid,
    partition_number AS partitionnum,
    avg_fragmentation_in_percent AS frag
INTO #work_to_do
FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, 'LIMITED')
WHERE avg_fragmentation_in_percent > 10.0 AND index_id > 0;

-- Declare the cursor for the list of partitions to be processed.
DECLARE partitions CURSOR FOR SELECT * FROM #work_to_do;

-- Open the cursor.
OPEN partitions;

-- Loop through the partitions.
WHILE (1=1)
    BEGIN;
        FETCH NEXT
           FROM partitions
           INTO @objectid, @indexid, @partitionnum, @frag;
        IF @@FETCH_STATUS < 0 BREAK;
        SELECT @objectname = QUOTENAME(o.name), @schemaname = QUOTENAME(s.name)
        FROM sys.objects AS o
        JOIN sys.schemas as s ON s.schema_id = o.schema_id
        WHERE o.object_id = @objectid;
        SELECT @indexname = QUOTENAME(name)
        FROM sys.indexes
        WHERE  object_id = @objectid AND index_id = @indexid;
        SELECT @partitioncount = count (*)
        FROM sys.partitions
        WHERE object_id = @objectid AND index_id = @indexid;

-- 30 is an arbitrary decision point at which to switch between reorganizing and rebuilding.
        IF @frag < 30.0
            SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REORGANIZE';
        IF @frag >= 30.0
            SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REBUILD';
        IF @partitioncount > 1
            SET @command = @command + N' PARTITION=' + CAST(@partitionnum AS nvarchar(10));
        EXEC (@command);
        PRINT N'Executed: ' + @command;
    END;

-- Close and deallocate the cursor.
CLOSE partitions;
DEALLOCATE partitions;

-- Drop the temporary table.
DROP TABLE #work_to_do;
GO

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

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