zoukankan      html  css  js  c++  java
  • 了解NTFS压缩

    在您选中“压缩内容以节省磁盘空间”复选框之前,最好先了解一下这对磁盘上运行的快乐的小字节、字节和半字节有何影响。
    备份应用程序在备份压缩文件时通常会收到ERROR U DISK U FULL errors,当驱动器上还有几GB的可用空间时,这会导致相当大的混乱。复制压缩文件时也可能出现其他问题。本文的目标是让读者更全面地了解压缩NTFS文件时到底发生了什么。

    Compression Units

    NTFS使用一个名为“压缩单元”的参数来定义数据流中压缩字节范围的粒度和对齐方式。压缩单元的大小完全基于NTFS簇大小(有关详细信息,请参阅下表)。在下面的描述中,缩写“CU”用于描述压缩单元和/或其尺寸。
    CU的默认大小是16个簇,尽管CU的实际大小实际上取决于磁盘的簇大小。下面的图表显示了与每个有效的NTFS簇大小相对应的CU大小。

    Cluster Size Compression Unit Compression Unit (hex bytes)
    512 Bytes 8 KB 0x2000
    1 KB 16 KB 0x4000
    2 KB 32 KB 0x8000
    4 KB 64 KB 0x10000
    8 KB 64 KB 0x10000
    16 KB 64 KB 0x10000
    32 KB 64 KB 0x10000
    64 KB 64 KB 0x10000

    本机NTFS压缩在群集大小大于4KB的卷上不起作用,但仍可以使用稀疏文件压缩。

    NTFS稀疏文件

    NTFS的稀疏文件特性允许应用程序创建非常大的文件,这些文件主要由零范围组成,而无需为零范围实际分配LCN(逻辑群集)。对于代码头,可以通过使用FSCTL_SET_SPARSE IO控制代码调用DeviceIoControl来完成,如下所示。

    BOOL SetSparse(HANDLE hFile)
         {
               DWORD Bytes;
               return DeviceIoControl(hFile, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &Bytes, NULL);
         }

    若要指定零范围,则应用程序必须使用FSCTL_SET_ZERO_DATA IO控制代码调用DeviceIoControl。

    BOOL ZeroRange(HANDLE hFile, LARGE_INTEGER RangeStart, LONGLONG RangeLength)
         {
                FILE_ZERO_DATA_INFORMATION FileZeroData;
                DWORD Bytes;
                FileZeroData.FileOffset.QuadPart = RangeStart.QuadPart;
                FileZeroData.BeyondFinalZero.QuadPart = RangeStart.QuadPart + RangeLength + 1;
                return DeviceIoControl( hFile,
                                         FSCTL_SET_ZERO_DATA,
                                         &FileZeroData,
                                         sizeof(FILE_ZERO_DATA_INFORMATION),
                                         NULL,
                                         0,
                                         &Bytes,
                                         NULL);
         }

    因为稀疏文件实际上不会为零范围分配空间,所以稀疏文件可以比父卷大。为此,NTFS创建一个占位符VCN(虚拟集群号)范围,不映射逻辑集群。任何访问“稀疏”范围的尝试都会导致NTFS返回一个满是零的缓冲区。访问分配的范围将导致对分配范围的正常读取。当数据写入稀疏文件时,会创建一个与包含写入字节的压缩单元边界完全对齐的分配范围。请参阅下面的示例。如果虚拟集群号vcn0x3a发生单字节写入,那么所有压缩单元3(vcn0x30-0x3f)将成为分配的LCN(逻辑集群号)范围。分配的LCN范围将填充零,并且单个字节将写入目标LCN中适当的字节偏移量。

    [...] - ALLOCATED
    (,,,) - Compressed
    { } - Sparse (or free) range
       / 00000000000000000000000000000000000000000000000000000000000000000000000000000000
    VCN 00000000000000001111111111111111222222222222222233333333333333334444444444444444
        0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
                CU0 CU1 CU2 CU3 CU4
         |++++++++++++++||++++++++++++++||++++++++++++++||++++++++++++++||++++++++++++++|
         { }[..............]{ }
    Extents {
        VCN = 0x0 LEN = 0x30 CU0 - CU2
        VCN = 0x30 LEN = 0x10: LCN = 0x2a21f CU3
        VCN = 0x10 LEN = 0x10 CU4
    }

    下面是使用稀疏文件API创建的2GB文件的屏幕截图。

    请注意,这个卷只有76.9MB,但在根文件夹中有一个2GB的文件。

    如果我们试图用COPY命令复制这个稀疏文件,它将失败。这是因为COPY不知道如何复制文件上的稀疏属性,所以它试图在D:的根目录中创建一个真正的2GB文件。当尝试将大型数据库文件从一个卷移动到另一个卷时,可能会发生这种情况。如果您的数据库应用程序使用稀疏属性,那么在将数据库移动到其他卷时,最好使用数据库软件的备份/还原功能。

    现在让我们用COMPACT实用程序查看文件的属性。请注意,该文件显示为压缩文件,并且具有巨大的压缩比。

    如果您返回并从资源管理器查看文件属性,您将注意到没有压缩复选框(或任何其他指示文件已压缩)。这是因为shell不检查文件中的稀疏位。

    简而言之,在将稀疏文件从一个位置移动到另一个位置时要小心。应用程序告诉文件系统零范围的偏移量,因此您应该始终将稀疏文件的管理留给创建它们的应用程序。手动移动或复制稀疏文件可能会导致意外结果。

    NTFS Compression

    既然我们已经讨论了稀疏文件,我们将继续讨论传统的NTFS压缩。NTFS通过将数据流分成CU来压缩文件(这与稀疏文件的工作方式类似)。当创建或更改流内容时,数据流中的每个CU都被单独压缩。如果压缩导致减少一个或多个群集,则压缩单元将以其压缩格式写入磁盘。然后将稀疏VCN范围固定到压缩VCN范围的末尾以进行对齐(如下例所示)。如果数据压缩不足以将一个集群的大小缩小,那么整个CU将以未压缩的形式写入磁盘。
    这种设计使得随机访问非常快,因为只有一个CU需要解压缩才能访问文件中的任何单个VCN。不幸的是,大型顺序访问相对较慢,因为许多CU的解压需要执行顺序操作(如备份)。
    在下面的示例中,压缩文件由六组映射对(编码的文件范围)组成。三个分配的范围与三个稀疏范围共存。稀疏范围的目的是保持压缩单元边界上的VCN对齐。这可以防止NTFS在用户希望读取文件中的小字节范围时不得不解压缩整个文件。第一个压缩单元(CU0)压缩了12.5%(这使得分配的范围缩小了2个VCNs)。在文件扩展数据块中添加了一个额外的空闲VCN范围,作为CU尾部释放的lcn的占位符。第二个分配的压缩单元(CU1)与第一个相似,只是CU压缩了大约50%。
    NTFS不能压缩CU2和CU3,但部分CU4可压缩69%。因此,CU2和CU3未压缩,而CU4从VCN 0x40压缩到0x44。因此,CU2、CU3和CU4是一个单独的运行,但该运行包含压缩和未压缩VCN的混合。
    注意:每组括号代表已分配或可用空间的连续运行。一组NTFS映射对描述了每组括号。

    [...] - ALLOCATED
    (,,,) - Compressed
    { } - Sparse (or free) range
       / 00000000000000000000000000000000000000000000000000000000000000000000000000000000
    VCN 00000000000000001111111111111111222222222222222233333333333333334444444444444444
        0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
               CU0 CU1 CU2 CU3 CU4
         |++++++++++++++||++++++++++++++||++++++++++++++||++++++++++++++||++++++++++++++|
         (,,,,,,,,,,,,){}(,,,,,,){ }[...............................,,,,){ }
    Extents {
        VCN = 0x0 LEN = 0xe : LCN = 0x29e32d CU0
        VCN = 0xe LEN = 0x2 CU0
        VCN = 0x10 LEN = 0x8 : LCN = 0x2a291f CU1
        VCN = 0x18 LEN = 0x8 CU1
        VCN = 0x20 LEN = 0x25 : LCN = 0x39dd49 CU2 - CU4
        VCN = 0x45 LEN = 0xb CU4
    }

    现在我们来讨论这个设计的局限性。下面是一些在读/写压缩文件时出错的例子。

    Disk full error during a backup read operation or file copy

    1. NTFS确定正在访问哪个压缩单元。
    2. 读取压缩单元的整个分配范围。
    3. 如果单元没有被压缩,那么我们跳到第5步。否则,NTFS将尝试保留(但不分配)将解压缩的CU写回磁盘所需的空间。如果磁盘上的可用空间不足,则应用程序在读取期间可能会出现错误“磁盘已满”。
    4. CU将在内存中解压缩。
    5. 解压后的字节范围将映射到缓存中并返回到请求应用程序。
    6. 如果CU的一部分在缓存中被改变…
      步骤3中的保留磁盘空间将变为已分配空间。
      铜的含量将被压缩并冲洗回新分配的区域(LCN位置通常不会改变)。
      CU中的任何可恢复磁盘空间都将被释放。

    Failure to copy a large file to a compressed folder

    这是压缩中最常见的问题,目前的解决方案是教育用户了解限制。NTFS压缩大约为每16个数据簇创建一个文件片段。因为标准压缩允许的最大集群大小是4K,所以允许的最大压缩单元是64KB。为了将一个100GB的文件压缩成64KB的部分,最终可能会有1638400个片段。编码1638400个片段对于文件系统来说是有问题的,并且可能导致创建压缩文件失败。在Vista及更高版本上,文件复制将失败,并受到状态“文件”和“系统”的限制。在早期版本中,状态代码为statusu unficientu RESOURCES。如果可能,请避免对较大或对系统性能至关重要的文件使用压缩。
    我收到了来自NTFS主要开发负责人关于这个博客的反馈。幸运的是,大多数反馈都很好,但他要求我增加一个最大尺寸的建议。根据我们开发团队的研究,对于集群大小为4KB的卷上的压缩文件,50-60GB是一个“合理的大小”。对于集群大小较小的卷,这个“合理大小”会急剧下降。

    压缩.VHD(虚拟硬盘)文件会导致虚拟机性能降低

  • 相关阅读:
    python中的编码与解码
    python中的迭代器
    python中高阶函数与装饰器(3)
    python中高阶函数与装饰器(2)
    python中高阶函数与装饰器
    python中几种常用的数据类型
    python 启航
    Python [习题] 字典排序
    SQL-TSQL
    SQL基础语句
  • 原文地址:https://www.cnblogs.com/yilang/p/13582094.html
Copyright © 2011-2022 走看看