如何在node.js中的单个进程内同步对文件的访问?

Eva*_* P. 6 synchronization flock fs node.js

我有一个Web服务器,可以读写磁盘上的数据文件.我想只在一个Web请求中写入一个文件.

这是一个示例程序,说明了我的问题.它将状态文件保存在"/tmp/rw.txt"中,并在每次Web命中时增加整数内容.运行此程序,然后运行类似的程序ab -n 10000 -c 1000 http://localhost:3000/,表明通过多次点击从文件中读取相同的值,并且它被多次写入.

注意:我知道flock()和fs-ext.但是,flock()会将文件锁定到当前进程; 因为这里的所有访问都在同一个进程中,所以flock()不起作用(并且大大复杂化了这个例子).

另请注意,我通常使用express,async等来完成大部分工作; 为了举例,只是坚持基础.

var http = require("http"),
    fs = require("fs");

var stateFile = "/tmp/rw.txt";

var server = http.createServer(function(req, res) {

    var writeNum = function(num) {
        var ns = num.toString(10);
        console.log("Writing " + ns);
        fs.writeFile(stateFile, ns, function(err) {
            if (err) {
                res.writeHead(500, {"Content-Type": "text/plain"});
                res.end(err.message);
            } else {
                res.writeHead(200, {"Content-Type": "text/plain"});
                res.end(ns);
            }
        });
    };

    switch (req.url) {
    case "/reset":
        writeNum(0);
        break;
    case "/":
        fs.readFile(stateFile, function(err, data) {
            if (err && err.code == "ENOENT") {
                // First time, set it to zero
                writeNum(0);
            } else if (err) {
                res.writeHead(500, {"Content-Type": "text/plain"});
                res.end(err.message);
            } else {
                writeNum(parseInt(data, 10) + 1);
            }
        });
        break;
    default:
        res.writeHead(404, {"Content-Type": "text/plain"});
        res.end("No such resource: " + req.url);
    }
});

server.listen(3000);
Run Code Online (Sandbox Code Playgroud)

Eva*_* P. 2

我无法找到一个可以完成我想要的功能的库,所以我在这里创建了一个:

https://npmjs.org/package/schlock

这是上面使用读/写锁定的示例程序。我还使用了“Step”来使整个内容更具可读性。

var http = require("http"),
    fs = require("fs"),
    Schlock = require("schlock"),
    Step = require("step");

var stateFile = "/tmp/rw.txt";

var schlock = new Schlock();

var server = http.createServer(function(req, res) {

    var num;

    Step(
        function() {
            schlock.writeLock(stateFile, this);
        },
        function(err) {
            if (err) throw err;
            fs.readFile(stateFile, this);
        },
        function(err, data) {
            if (err && err.code == "ENOENT") {
                num = 0;
            } else if (err) {
                throw err;
            } else {
                num = parseInt(data, 10) + 1;
            }
            fs.writeFile(stateFile, num.toString(10), this);
        },
        function(err) {
            if (err) throw err;
            schlock.writeUnlock(stateFile, this);
        },
        function(err) {
            if (err) {
                res.writeHead(500, {"Content-Type": "text/plain"});
                res.end(err.message);
            } else {
                res.writeHead(200, {"Content-Type": "text/plain"});
                res.end(num.toString(10));
            }
        }
    );
});

server.listen(3000);
Run Code Online (Sandbox Code Playgroud)