如何要求连续块(非碎片)时,附加或创建文件在c?

jaxagkaj  于 2021-06-15  发布在  Mysql
关注(0)|答案(4)|浏览(367)

所以我想了解dbms实现是如何工作的
举个例子:
mysql实现每个表都有自己的页面,页面大小为16kb
所以每个表都是一个文件,是16kb的倍数,考虑到它有多大,需要多少页
现在我在某个地方读到,这些页面在磁盘映像或内存映像中不会变得支离破碎,所以我的问题是,如何?
dbms开发人员如何告诉操作系统“嘿,我刚刚添加了一个16kb的数据(页面)到这个文件中,但是使这个页面不会变得支离破碎?”
是不是因为内存映像实际上没有显示字节在磁盘上的实际存储方式及其逻辑关系?
或者是因为这些dbms不知何故要求o.s确保这些16kb字节的块不会被碎片化?
如何在c语言中做到这一点?

xriantvc

xriantvc1#

在严格一致的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() 功能应确保在文件系统存储介质上分配从偏移量开始并持续len字节的常规文件数据所需的任何存储。如果 posix_fallocate() 如果返回成功,则对指定文件数据的后续写入不会由于文件系统存储介质上缺少可用空间而失败。
不过,请再次注意,无法确保底层系统如何确保对文件的后续写入成功。
如果文件空间是连续的,它仍然是“实现定义的”。文件系统很可能会将保留的空间作为一个连续的块来分配,但这绝对不能保证。
linux提供了 fallocate() 功能:
简介


# 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引用的文件操作分配的磁盘空间,从offset开始到len bytes。
...
请注意,这是如何显式地列为“不可移植的,linux特定的”。
甚至是不可移植的,特定于linux的 fallocate() 函数绝对不能保证连续文件的分配。
因为实际的空间分配是一个依赖于文件系统的操作。
例如,xfs尝试预先分配文件空间,以便将数据存储在连续的块中。
但同样,没有任何保证。
只有oracle的hsm(sun的sam qfs)和ibm的spectrum scale(最初称为gpfs)等高性能文件系统才能提供必要的控制级别,使您甚至有机会获得文件中连续的空间分配。
例如,oracle hsm/qfs setfa() 功能:
名称

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() 无法用于获取文本文件中的字节数。
krcsximq

krcsximq2#

如何在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和文件系统协同工作来实现这一点。如果我写16k,文件系统必须收集4个不连续的4k扇区来存储它,它会将read()和write()调用安排为不受此布局的影响--它将数据传递到几乎相邻的区域,并从中传递数据。类似地,如果16k缓冲区需要4个不连续的4k物理内存页,vm系统会安排页Map来构建一个连续的虚拟范围。
也就是说,有些文件系统支持预先分配物理上相邻的磁盘区域的机制(尽管使用卷管理、san、虚拟化这主要是假装的),这样文件系统就可以实现性能目标,并以牺牲可移植性为代价。
)-这似乎是一个相当简单的想法,我可以调用fsync()、fdatasync()、sync()或类似的方法。是的,不。这个http://blog.httrack.com/blog/2013/11/15/everything-you-always-wanted-to-know-about-fsync/ 处理得很好。热释光;dr-os/filesystem对真相的松散理解会让编译器供应商脸红。

gajydyqb

gajydyqb3#

现在我在某个地方读到,这些页面在磁盘映像或内存映像中不会变得支离破碎,所以我的问题是,如何?
数据库必须预先分配文件。
dbms开发人员如何告诉操作系统“嘿,我刚刚添加了一个16kb的数据(页面)到这个文件中,但是使这个页面不会变得支离破碎?”
这必须通过系统服务来完成。
是不是因为内存映像实际上没有显示字节在磁盘上的实际存储方式及其逻辑关系?不。
或者是因为这些dbms不知何故要求o.s确保这些16kb字节的块不会被碎片化?
同样,你必须做一个连续的扩展,一个很有可能失败的扩展。
如何在c语言中做到这一点?
你不能在标准c中这样做。但是,任何设计合理的操作系统都会有允许您分配连续文件的服务。

ddarikpa

ddarikpa4#

50年前,你的问题是计算机科学和工程领域的热门主题。但今天不行。
几乎每个硬盘都有512字节的分配单元。cd的au值为2kb。某些ssd在为mysql调优时,其au为16kb。
有许多不同的“文件系统”。windows至少有fat-32和ntfs*尼克斯有很多。每个人都为自己在某些方面做得更好而自豪。但自由空间管理与分配单元的大小有关。还记得当磁盘越来越大的时候,dos对fat-16的麻烦吗?名称中的“16”表示最多有2^16个块的磁盘。这迫使2gb磁盘驱动器的分配单元为32kb!典型的系统有很多小文件,实际上一半的磁盘可能被浪费了!
我说的是“分配单元”,因为这基本上是防止操作系统考虑将块分散在驱动器周围的唯一方法。
让我们从市场营销的Angular 来看你的问题。如果碎片化是个大问题,那么
新的、更好的文件系统将会出现来解决这个问题——尽管不一定像您提到的那样简单。
操作系统已经知道了这个问题,所以他们有办法“尝试”分块分配。但他们总是愿意在必要的时候给你一些小东西。
mysql的innodb(大约2000年)在4mb(?)的“范围”中进行了大量的分配,希望得到连续分配的磁盘。但当它失败时,什么也不会崩溃。
软件会绕过这个问题,比如使用“原始驱动器访问”。但请注意,这并不是“如何优化您的数据库”的首要问题?如果有的话,它会被放在“哦,顺便说一句”章节里。
几十年前,有一些oss可以让你预先分配一个“连续”的文件。我最近没听说过这样的事。
企业系统通过使用带有电池备份写缓存的硬件raid控制器解决了这个问题。不仅分散聚集对用户是隐藏的,而且由于崩溃安全缓存,写入变得“即时”。
ssd没有任何寻道时间(不像hdd),所以一个块是否被切碎并不重要。当然,有一些代码可以处理它,但这与传输、校验和、互斥、系统调用等时间相比实在微不足道。
我有一个经验法则:如果一个潜在的优化看起来没有10%的帮助,我就放弃它,转而做别的事情。我建议你继续。

相关问题