更新一个随时可能被访问的文件 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
notcome
V2EX    Node.js

更新一个随时可能被访问的文件

  •  
  •   notcome 2014-05-06 16:10:25 +08:00 4214 次点击
    这是一个创建于 4228 天前的主题,其中的信息可能已经有所发展或是发生改变。
    有一组 Markdown 文档,用户请求、渲染、输出 HTML。

    request /a => load /path/a.md => render => HTML => user
    request /enoent => load /path/enoent.md => 404 => user

    我希望实现一个可以动态更新的功能,

    1. buffer => tmpfile
    2. mv /path/foo => /history/bar
    3. mv tmpfile => /path/foo

    如果在 2、3 之间加载 /path/foo,那么可能会导致一个 404 错误。如果我同步而不是异步重命名,能解决这个问题吗?

    fs.renameSync('/path/foo', '/history/bar');
    fs.renameSync('tmpfile', '/path/foo');

    我担心的问题是,如果之前已经有请求异步的读取 /path/foo,然后因为操作系统的调度原因,拖到 2、3 之间执行。这种情况可能发生吗?

    1. fs.readFile('/path/foo', cb);
    2. fs.renameSync('/path/foo', '/history/bar');
    3. OS reads file /path/foo => not found => ENOENT
    4. call cb of step 1.
    5. fs.renameSync('tmpfile', '/path/foo');

    以及,有没有异步更新该文件的方法?我想到的是建立一个 fs layer,当更新操作到达之后,block 所有对该文件的访问,直至更新结束后。但是似乎太复杂了啊…………
    12 条回复    2014-05-06 23:16:39 +08:00
    merlin852
        1
    merlin852  
       2014-05-06 17:05:44 +08:00
    2. mv -->cp
    不懂js,瞎猜的
    shiye515
        2
    shiye515  
       2014-05-06 17:11:55 +08:00
    我司的cms就能实现这种需求,不过我一个小前端没研究过是怎么实现的
    ibudao
        3
    ibudao  
       2014-05-06 17:44:07 +08:00
    主从备份不就是处理这种场景的么。。request的handler这样写:
    if exists /path/foo then return;
    else return /path/foo.bak;
    你只需要保证每份资源有一个冗于备份/path/*.bak 。
    notcome
        4
    notcome  
    OP
       2014-05-06 18:01:52 +08:00 via iPhone
    @ibudao 很好的方案……但是假如很倒霉……然后 foo 不存在,接着跑去试 foo.bak 的时候 foo 已删除怎么办……延迟删除吗?

    以及这样似乎拷贝了好多冗余信息。
    rrfeng
        5
    rrfeng  
       2014-05-06 18:17:36 +08:00
    mv foo foo.bak
    mv tmp foo
    rm foo.bak

    再配合 if exists
    Mutoo
        6
    Mutoo  
       2014-05-06 18:20:41 +08:00
    先内存缓存,然后再文件IO.
    Ever
        7
    Ever  
       2014-05-06 18:23:19 +08:00
    写入filename.new, 再mv filename.new filename就行。

    一般情况下, 打开一个文件获取到一个fd不关闭, 就算期间这个文件被删除或者被mv替换,通过保留的fd还是能读完原文件。
    tangzx
        8
    tangzx  
       2014-05-06 19:55:16 +08:00 via iPhone
    楼主放心,如果调用sync自然会block整个程序,不用再额外写了
    notcome
        9
    notcome  
    OP
       2014-05-06 20:12:09 +08:00
    @Ever 这我明白,我担心的是 foo 不存在的那一刻查找 foo。

    @rrfeng 我担心查找 foo 的请求在前两步 mv 之间出现。

    @tangzx 谢谢,我主要担心 block 整个程序但是 kernel 还在以稀奇古怪地方式处理 I/O,可能我对进程、内核态之间的关系理解有误。

    @Mutoo 感觉太复杂了,但是我最终打算采取类似的方案突然想起我似乎还要实现一个权限管理系统,封装 fs 成最佳选择(“突然想起”,这个项目要坑啊)
    rrfeng
        10
    rrfeng  
       2014-05-06 22:08:26 +08:00
    @notcome
    写错了,第一个 mv 改成 cp

    仔细想想其实直接 mv / cp 覆盖被访问的文件,是不会存在 404 出现的状况的!
    这是由文件系统(内核)决定的!
    所以这样

    1. buffer => tmpfile
    2. cp /path/foo => /history/bar
    3. mv tmpfile => /path/foo

    把你的第二步 mv 换成 cp 就 OK 了……
    ibudao
        11
    ibudao  
       2014-05-06 22:21:54 +08:00
    在高并发的情形中,冗余备份显然比同步有更好的响应速度。但如果并发量不高,并且磁盘容量吃紧时,则同步的方案更好。权衡一下空间和时间,最终还是看你的需求。。
    notcome
        12
    notcome  
    OP
       2014-05-06 23:16:39 +08:00
    我明白了一个问题……
    mv a b 能直接把 b 覆盖掉……
    那我直接:
    ln foo bar
    mv tmp foo
    就可以了……
    我还是太愚蠢,打扰各位了,对不起!
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1203 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 22ms UTC 23:45 PVG 07:45 LAX 15:45 JFK 18:45
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86