Как запросить непрерывные блоки (не фрагментированные) при добавлении или создании файлов в C? - PullRequest
0 голосов
/ 20 декабря 2018

Итак, я хочу понять, как работает реализация СУБД.

. В качестве примера:

MySQL реализует каждую таблицу со своими собственными страницами, которые составляют 16 КБ

, поэтому каждая таблицаэто файл, кратный 16 КБ, учитывая его размер и, следовательно, сколько страниц ему нужно

Теперь я где-то читал, что эти страницы не фрагментируются в образ диска или образ памяти , поэтому мой вопрос: КАК?

как разработчики СУБД сообщают операционной системе, что «эй, я только что добавил данные 16 КБ (страницу) вэтот файл, но сделать эту страницу не фрагментированной "

потому что образ памяти не показывает, как байты действительно хранятся на диске, и его логика?

или это потому, что эти СУБД как-то просят ОС убедиться, что эти куски 16 КБ байтов не фрагментированы?

а как это сделать на С?

Ответы [ 4 ]

0 голосов
/ 21 декабря 2018

Теперь я где-то читал, что эти страницы не фрагментируются в образе диска или памяти, поэтому мой вопрос: КАК?

База данных должна предварительно выделить файлы.

как разработчики СУБД сообщают операционной системе, что «эй, я только что добавил данные (страницу) размером 16 КБ в этот файл, но сделать эту страницу не фрагментированной»

Это должно быть сделано через системные службы.

Это потому, что образ памяти не показывает, как байты действительно хранятся на диске, и его логика?Нет.

или это потому, что эти СУБД как-то просят ОС убедиться, что эти фрагменты размером 16 КБ не фрагментированы?

Опять же, вы должны сделать непрерывное расширение,что-то, что имеет высокую вероятность сбоя.

и как это сделать в C?

Вы не можете сделать это в стандартном C. Однако, любая рационально разработанная операционная системабудет иметь службы, позволяющие размещать смежные файлы.

0 голосов
/ 20 декабря 2018

В строго соответствующем коде C вы не можете.Стандарт C очень плохо понимает, что такое файл.Даже получить размер файла невозможно с помощью строго соответствующего C, кроме как открыть файл в двоичном режиме и прочитать его побитово и посчитать. * Просто не существует способа указать, каким будет файлхранится в соответствующем коде C.

Таким образом, вы можете использовать системные методы.

POSIX предоставляет posix_fallocate() функцию :

ОБОЗНАЧЕНИЕ

#include <fcntl.h>

int posix_fallocate(int fd, off_t offset, off_t len); [Option End]

ОПИСАНИЕ

Функция posix_fallocate() должна гарантировать, что любое необходимое хранилище для обычных данных файла начинается со смещенияи продолжение для длинных байтов выделяется на носителе хранения файловой системы.Если posix_fallocate() успешно возвращается, последующие записи в указанный файл не должны завершаться сбоем из-за недостатка свободного места на носителе файловой системы.

Обратите внимание, однако, что пути нетчтобы гарантировать, как базовая система гарантирует, что последующие записи в файл будут успешными.

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

Linux предоставляет fallocate() функция :

SYNOPSIS

   #define _GNU_SOURCE             /* See feature_test_macros(7) */
   #include <fcntl.h>

   int fallocate(int fd, int mode, off_t offset, off_t len);

ОПИСАНИЕ

Это непереносимый системный вызов для Linux.Для портативного, определенного POSIX.1 метода обеспечения выделения места для файла см. posix_fallocate(3).

fallocate(), позволяющий вызывающей стороне напрямую манипулировать выделенным дисковым пространством для файла, на который ссылаетсяfd для диапазона байтов, начинающегося со смещения и продолжающегося для длинных байтов.

...

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

И даже непереносимая специфичная для Linux функция fallocate() не дает абсолютно никаких гарантий относительно непрерывного размещения файлов.

Поскольку фактическое выделение пространства является зависимой от файловой системы операцией.

XFS, например, пытается предварительно выделить файловое пространство , чтобы данные хранились в смежных блоках.

Но опять же, без гарантий.

Только высокопроизводительные файловые системытакие как Oracle HSM (Sun SAM-QFS) и IBM Spectrum Scale (первоначально называвшийся GPFS), обеспечивают уровень контроля, необходимый для того, чтобы у вас даже был реальный шанс получить продолжениеиспользуя выделение пространства в файле.

Например, функция Oracle HSM / QFS setfa() :

NAME

sam_setfa - Sets attributes on a file or directory

ОПИСАНИЕ

 cc [ flag  ... ] file    ...  -L/opt/SUNWsamfs/lib  -lsam  [library ... ]

 #include "/opt/SUNWsamfs/include/lib.h"

 int sam_setfa(const char *path, const char *ops);

ОПИСАНИЕ

 sam_setfa() sets attributes on a file or directory  using  a
 SAM-QFS  system  call.  path is the file on which to set the
 attributes.  ops is the character  string  of  options,  for
 example:  "ds1".  Individual options are described below.

ОПЦИИ

 A n  Specifies the number of bytes to be allocated ahead  of
      a write to the file.  The n must be an integer and must
      be greater than or equal to one kilobyte and less  than
      4  terabytes.   The n is rounded down to units of kilo-
      bytes.  This option is only valid for a  regular  file.
      This  option  should  be  used when writing large files
      where more sequential  allocation  is  desired.   Note,
      when  the  file  is  closed the blocks are reset to the
      size of the file.

      ...

 l n  Specifies the number of bytes to be preallocated to the
      file.   The n must be an integer.  This option can only
      be applied to a regular file.  If an I/O event attempts
      to  extend  a  file preallocated with the L option, the
      caller receives an ENXIO error.  The l option allocates
      using  extent  allocation.   This means striping is not
      supported and the file is allocated on 1 disk device or
      1  striped  group.   The  L  and l options are mutually
      exclusive.  If the file has existing disk blocks,  this
      option is changed to the L option.

 L n  Specifies the number of bytes to be preallocated to the
      file.   The  n must be an integer.  This option is only
      valid for a regular file.  The L option allocates using
      standard allocation.  This means striping is supported.
      This also means the file can be extended.  The L and  l
      options are mutually exclusive.

      ...

Даже в высокопроизводительных, сложных, проприетарных файловых системах, которые предлагают множество опций для того, как файлы хранятся на диске, невозможно гарантировать непрерывное выделение пространства внутри файла.

Это одна из причин, по которой высокопроизводительная база данных может использовать необработанные устройства для хранения данных - это действительно единственный способ гарантировать непрерывное хранение данных.

* Нет, fseek() / ftell() не строго соответствует Cкод.fseek( fp, 0, SEEK_END ) - это явно неопределенное поведение в двоичном потоке , и ftell() нельзя использовать для получения количества байтов в текстовом файле .

0 голосов
/ 21 декабря 2018

50 лет назад ваш вопрос был горячей темой в области компьютерных наук и инженерии.Но не сегодня.

Практически каждый жесткий диск имеет единицу выделения 512 байт.Компакт-диски имеют AU 2 КБ.Некоторые SSD, настроенные для MySQL, имеют AU 16 КБ.

Существует много разных «файловых систем».В Windows есть (как минимум) FAT-32 и NTFS.* у nix многоКаждая ФС гордится тем, что делает что-то лучше.Но управление свободным пространством борется с размером единицы размещения.Помните, как хлопотал DOS с FAT-16, когда диски становились все больше и больше?«16» в названии относится к диску, имеющему до 2 ^ 16 блоков.Это заставило диск на 2 ГБ иметь выделенную единицу 32 КБ!В типичной системе было много маленьких файлов, буквально половина диска была, вероятно, потрачена впустую!

Я говорю о «единицах распределения», потому что это, по сути, единственный способ не дать ОС думать о разбросе блоков.вокруг диска.

Давайте посмотрим на ваш вопрос с маркетинговой точки зрения.Если фрагментация настолько важна, то

  1. Новые, более совершенные файловые системы могут решить проблему - хотя и не обязательно так, как вы упомянули.
  2. Операционные системызнали о проблеме, поэтому у них есть способы «попытаться» распределить их по частям.Но они всегда готовы дать вам маленькие кусочки, когда это необходимо.
  3. MySQL InnoDB (около 2000 г.) приложил немало усилий для выделения в «экстентах» 4 МБ (?) В надежде получить непрерывно распределенный диск.Но при сбое ничего не происходит.
  4. Программное обеспечение может обойти проблему, например, с помощью «доступа к сырому диску». Но обратите внимание, что это не в авангарде «как оптимизировать вашу базу данных»? Если дажедоступно, оно скрыто в главе «О, кстати».

Несколько десятилетий назад были некоторые ОС, которые позволяли бы вам предварительно выделить файл, который был «смежным».В последнее время о таком не слышали.

Корпоративные системы решили проблему с помощью аппаратных RAID-контроллеров с кэш-памятью с резервным питанием от батареи. Мало того, что сборка разброса будет скрыта от пользователя, но и запись станет «мгновенной» из-закэш-память, устойчивая к сбоям.

SSD не имеют времени на поиск (в отличие от жестких дисков), поэтому действительно не имеет значения, если блок разбит. Конечно, есть некоторый код, чтобы с ним работать, ноэто действительно незначительно по сравнению с передачей, контрольной суммой, мьютексом, системным вызовом и т. д. и т. д.

У меня есть правило: если потенциальная оптимизация неЯ думаю, что это поможет на 10%, я бросаю его и перехожу к чему-то другому.Я предлагаю вам двигаться дальше.

0 голосов
/ 20 декабря 2018

как это сделать в C:

int add16k(void *My16kDataChunk) {
    fd = open(“My.DataBase”, O_WRONLY|O_APPEND);
    if (fd != -1) {
         write(fd, My16kDataChunk, 16*1024);
         close(fd);
    }
    return fd != -1;
}

Но для базы данных вы можете кэшировать дескрипторы открытых файлов, иметь возможность записи с произвольным смещением, убедиться, чточто данные действительно записаны (*) и т. д. Самое главное, вы хотите убедиться, что несколько запросов не мешают друг другу.В обратном направлении вам нужны: синхронизация, fdatasync, pwrite.

образ памяти не отображается ... Это потому, что образ памяти идентичен тому, что находится на диске.Две подсистемы, VM и FileSystem, взаимодействуют для достижения этой цели.Если я записываю 16k, а файловая система должна собирать 4 непрерывных 4k сектора для его хранения, она организует мои вызовы read () и write () так, чтобы они не обращали внимания на эту компоновку - она ​​доставляет данные в и из смежных областей.Точно так же, если 16-килобайтный буфер требует 4-х непрерывных 4-килобайтных страниц физической памяти, система виртуальных машин организует отображения страниц для создания непрерывного виртуального диапазона.

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

(*) - это выглядит как довольнопростая идея, я могу просто вызвать fsync (), fdatasync (), sync () или что-то подобное.Да нетЭто http://blog.httrack.com/blog/2013/11/15/everything-you-always-wanted-to-know-about-fsync/ дает довольно хорошее отношение к этому.TL; DR - люди из OS / FileSystem, потерявшие представление об истине, заставили бы производителя компилятора покраснеть.

...