C++ 示例:并发加载
FilePortionSource
示例演示了如何使用并发加载。此示例是对 FileSource
示例进行的改进。每个输入文件都会拆分成多个部分并分发到 FilePortionSource
实例。源接受将输入分成多个部分所依据的偏移量列表;如果未提供偏移量,源将动态拆分输入。
并发加载将在工厂中进行处理,所以本文讨论的重点是 FilePortionSourceFactory
。该示例的完整代码位于 /opt/vertica/sdk/examples/ApportionLoadFunctions
中。该分发还包括此示例的 Java 版本。
加载和使用示例
按如下所示加载并使用 FilePortionSource
示例。
=> CREATE LIBRARY FilePortionLib AS '/home/dbadmin/FP.so';
=> CREATE SOURCE FilePortionSource AS LANGUAGE 'C++'
-> NAME 'FilePortionSourceFactory' LIBRARY FilePortionLib;
=> COPY t WITH SOURCE FilePortionSource(file='g1/*.dat', nodes='initiator,e0,e1', offsets = '0,380000,820000');
=> COPY t WITH SOURCE FilePortionSource(file='g2/*.dat', nodes='e0,e1,e2', local_min_portion_size = 2097152);
实施
并发加载会在两个位置影响源工厂:getDesiredThreads()
和 prepareUDSourcesExecutor()
。
getDesiredThreads()
getDesiredThreads()
成员函数可确定要请求的线程数。Vertica 会在调用 prepareUDSourcesExecutor()
之前在每个执行程序节点上调用此成员函数。
该函数会先开始将输入文件路径(可能为 glob)分成多个单独的路径。本讨论省略了这些细节。如果未使用分摊加载,则该函数为每个文件分配一个源。
如果可以分摊源,则 getDesiredThreads()
会使用作为实参传递给工厂的偏移量,以将文件拆分成多个部分。然后,它会将这些部分分配给可用节点。此函数实际上不会直接分配源;完成这项工作是为了确定要请求的线程数。
该函数现在具有所有部分,因此可以知道部分的数量:
如果未提供偏移量,则该函数会将文件动态拆分成多个部分,每个线程一个部分。本讨论省略了此计算过程的细节。请求的线程数多于可用线程数没有意义,因此该函数会对用 PlanContext
(函数的实参)调用 getMaxAllowedThreads()
来设置上限:
有关此函数如何将文件拆分成多个部分的详细信息,请参阅完整示例。
此函数使用 vt_createFuncObject
模板来创建对象。Vertica 会调用使用此宏创建的返回对象的析构函数,但它不会调用其他对象(如向量)的析构函数。您必须自己调用这些析构函数以避免内存泄漏。在此示例中,这些调用是在 prepareUDSourcesExecutor()
中进行的。
prepareUDSourcesExecutor()
prepareUDSourcesExecutor()
成员函数(如 getDesiredThreads()
)包含单独的代码块,具体取决于是否提供了偏移量。在这两种情况下,该函数都会将输入拆分成多个部分并为它们创建 UDSource
实例。
如果使用偏移量调用函数,则 prepareUDSourcesExecutor()
会调用 prepareCustomizedPortions()
。此函数如下所示。
如果未使用偏移量调用 prepareUDSourcesExecutor()
,则它必须决定要创建的部分数。
基本规则是每个源使用一个部分。但是,如果有额外的线程可用,该函数会将输入拆分成更多部分,以便源可以同时处理它们。然后,prepareUDSourcesExecutor()
会调用 prepareGeneratedPortions()
以创建这些部分。该函数会先开始在计划上下文中调用 getLoadConcurrency()
以找到可用的线程数。
有关详细信息
有关此示例的完整实施,请参阅源代码。