Некоторые особенности работы QUEUE

Не так давно по эхам «пробегало» письмо, в котором автор сетовал на невозможность сортировки очереди по полям типа $STRING.

Это действительно так. Но! Это — не глюк Клариона! Это — особенность внутренней реализации структур, основанных на GROUP.

Дело в том, что структуры на основе GROUP имеют как бы двойной интерфейс доступа к полям.

Первый интерфейс — прямое обращение к полю структуры по его метке, которое обрабатывается компилятором на этапе создания программы. При этом, естественно, компилятору доступна ВСЯ информация по типам переменных. Соответственно этим типам ведется и работа с такими полями.

Второй интерфейс — косвенная работа со структурами QUEUE и FILE типа сортировок очереди. Вся эта работа проводится так называемым драйвером. У FILE свои драйвера, у QUEUE так-же есть свой драйвер, который обрабатывает все обращения к очереди. В предыдущих своих письмах я вскользь упоминал о нем.

Так вот, этот драйвер работает с полями очереди на основании той информации о них, которая создается компилятором на этапе компиляции программы и которая доступна по ссылке из заголовка очереди.

Но! Вся беда в том, что компилятор при создании этого описания полей не дает полного описания некоторых типов! Это, как раз, касается всех реферал-типов. В описании полей такие поля описываются просто как указатель. И все! Без конкретизации — на какой тип данных они указывают.

Естественно, что по этой информации драйвер очереди и не предполагает — какой тип данных скрывается под таким указателем. Поэтому и невозможна сортировка или поиск по полям типа $STRING/$CSTRING/$PSTRING, т.к. вся эта работа производится драйвером очереди, который воспринимает такие поля как простые указатели на область памяти.

Что можно посоветовать? Для строковых полей, по которым возможна сортировка или поиск, просто не надо использовать $STRING. Не бойтесь использовать обычные STRING с большой длинной! Как я уже писал в предыдущих письмах по данной теме, очереди с длиной записи > 127 бит ужимаются по спец. алгоритму. А накладные расходы, связанные со сжатием/распаковкой записи, не столь значимы, чтобы как-то существенно замедлить работу с такими очередями.

Кстати! Данный подход, наоборот, может уменьшить объем памяти, необходимый для хранения таких очередей.

Например.
используем тип &STRING

запись с пустой строкой (память под строку не выделялась) будет иметь размер 8 байт (тип &STRING занимает 2 LONG`а) запись со строкой, например, «1111111111», будет иметь размер также 8 байт, но, дополнительно, для хранения строки мы выделим через New(STRING(10)) как минимум еще 10 байт. Почему, как минимум? Не надо забывать про заголовок выделенной области памяти, который используется менеджером памяти Windows.
Итого, как минимум, 18 байт.

запись со строкой, например, «1234567890».
Также, как минимум, 18 байт.

используем STRING(255)

из-за сжатия размер будет 2+1 = 3байта!
2байта — на размер (255)
1байт  — на символ повторения (‘<32>’)

размер — (1+1)+(2+1) = 5байт!
1байт  — на размер (10)
1байт  — на символ повторения (‘1’)
2байта — на размер (245)
1байт  — на символ повторения (‘<32>’)

размер — (1+10)+(2+1) = 14байт!
1байт  — на признак несжатых данных
10байт — именно сами данные (‘1234567890’)
2байта — на размер (245)
1байт  — на символ повторения (‘<32>’)

При размере такой строки < 32 байт надо отнять по одному байту «на размер» в каждом варианте, а при размере > 8191 — добавить по одному байту «на размер». Как видно, практически в любом случае имеем выигрыш! При больших очередях можем получить приличную экономию!
Например, при Records()=1.000.000 записей:
а) 5 * 1000000 = ~5Mb!
б) 13 * 1000000 = ~13Mb!
в) 4 * 1000000 = ~4Mb!
К этому надо еще добавить, что в таких очередях будут паковаться ВСЕ поля. Вообще, строго говоря, в данном случае паковка идет не по полям а по всей записи без разбивки по полям. Т.е. в данном случае запись воспринимается как простой байтовый массив! Таким образом, например, несколько идущих подряд целочисленных полей, имеющих значение 0 (ноль), будут сжаты до 2-4байт (в зависимости от общего размера).

P.S.Естественно, все это относится к версиям C5 и C55. Ранние версии не поддерживают сжатия, за исключением, конечно, усекания пустых «хвостов» строк, если они стоят последними в записи.