Perl SQL和文件创建竞争条件

时间:2015-01-09 14:05:22

标签: sql-server perl race-condition

我如何处理"竞争条件"计划在每分钟运行的脚本实例之间,为目录中的每个文件执行以下任务:

  1. 连接到SQL数据库并检查表
  2. 中的最后一个元素(文件名)
  3. 使用下一个可用文件名创建多个文件(多个文件夹)
  4. 使用文件名和创建的文件插入SQL新记录'信息
  5. 由于流程每1分钟运行一次,因此2个实例可能会重叠并处理相同的文件。我可以通过文件锁定和跳过已打开的文件来防止这种情况,但问题仍然存在:

    • 检查数据库中的下一个可用文件名(2个进程要使用相同的文件名)
    • 使用此文件名创建文件

    进程A接受inputA.jpg并找到下一个可用的文件名image_01。

    进程B接受inputB.jpg并找到下一个可用的文件名image_01。

    所以混乱开始......

    不幸的是,我无法在SQL表中插入任何占位符记录来显示正在处理下一个文件名。

    循环的伪代码:

    foreach ($file)
    {
       $name = findFileNameInSql($file)
       $path1 = createFile($name, $settings1);
       $path2 = createFile($name, $settings2);
       $path3 = createFile($name, $settings3);
       addToSql($file, $name, $path1, $path2, $path3)
    }
    

    实际代码有点复杂,包括文件修改和2个SQL表的事务插入。如果createFile()失败,应用程序将回滚所有先前创建的文件。当一个app实例正在创建文件时,它显然会产生问题" abc"和第二个实例有错误的文件" abc"已经存在。

    编辑:

    当然,限制脚本只有一个实例可能是解决方案,但我希望找到一种方法来并行运行它们。如果没有办法,我们可以将其作为副本关闭。

1 个答案:

答案 0 :(得分:0)

您需要生成从数据库中的数据库原子返回下一个可用文件名的代码,以便数据库不能返回相同的文件名两次。这本身就是一个数据库问题,而不是一个perl问题。

您不会说出您正在使用的数据库,但有几种方法可以解决这个问题。 在MySQL中执行它的一种天真和野蛮的方法是让perl脚本在表上使用文件名执行LOCK TABLE表WRITE,同时计算新的并执行其工作。使用新文件名更新表后,您可以释放锁。表锁虽然不能很好地处理交易。

或者你可以做一些更优雅的事情,比如在数据库本身中实现具有适当锁定的存储过程以返回新文件名。

或者使用AUTOINCREMENT列,这样每次向表中添加内容时,都会得到一个新数字(因而是一个新文件名)。

但这一切都变得相当复杂;如果您同时拥有多个事务,数据库如何解析这些事务通常是可配置的事情,所以我无法告诉您将会发生什么。

鉴于您的代码主要是在重新组织磁盘上的数据,但同时运行多个作业并没有多大优势;无论如何,这段代码可能都是I / O绑定的。在这种情况下,只是为了使代码更改更简单,其他人建议一次只运行一个副本。