From aa2eaf0ff447617dbc1e34489aef186cd809bc98 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 28 Mar 2016 00:21:01 +0400 Subject: [PATCH] fix poor performance of fscache watcher handler --- plugins/c9.fs/fs.cache.xml.js | 198 +++++++++++++++++++--------------- 1 file changed, 113 insertions(+), 85 deletions(-) diff --git a/plugins/c9.fs/fs.cache.xml.js b/plugins/c9.fs/fs.cache.xml.js index bd9e1a70..b3bc5b43 100644 --- a/plugins/c9.fs/fs.cache.xml.js +++ b/plugins/c9.fs/fs.cache.xml.js @@ -82,6 +82,9 @@ define(function(require, exports, module) { node.status = "pending"; return; } + var parentPath = e.path; + if (!parentPath.endsWith("/")) + parentPath += "/"; // update cache if (!node) { if (!showHidden && isFileHidden(e.path)) @@ -96,93 +99,112 @@ define(function(require, exports, module) { // Indicate this directory has been fully read model.setAttribute(node, "status", "loaded"); - var wasOpen = startUpdate(node); - node.children = null; - var existing = node.map || {}; - node.map = {}; - - // Fill Parent - var ondisk = {}, toAppend = []; + var ondisk = Object.create(null); + var toRemove = []; + var toCreate = []; + var orphanAppand = []; + var existing = node.map || (node.map = Object.create(null)); e.result[1].forEach(function(stat) { if (!stat.name || !showHidden && isFileHidden(stat.name)) return; - var name = stat.name; - var path = (e.path + "/" + name).replace("//", "/"); + var path = parentPath + name; ondisk[name] = 1; - // if (existing[name]) return; + + if (existing[name]) + updateNodeStat(path, stat, existing[name]); + else + toCreate.push(stat); + if (orphans[path]) { - toAppend.push(path); + if (existing[name]) + delete orphans[path]; + else + orphanAppand.push(path); } - createNode(path, stat, existing[name], true); }); - for (var name in existing) { - if (!ondisk[name]) { - // onreaddir can be called before copied nodes are written to disk - // in this case we don't want to lose "predicted" state - if (existing[name] && existing[name].status === "predicted") - node.map[name] = existing[name]; - else { - delete existing[name]; - - emit("remove", { - path: e.path + "/" + name, - node: existing[name], - parent: node - }); - } - } - } + Object.keys(existing).forEach(function(name) { + // onreaddir can be called before copied nodes are written to disk + // in this case we don't want to lose "predicted" state + if (existing[name] && existing[name].status === "predicted") + ondisk[name] = 1; + if (!ondisk[name]) + toRemove.push(name); + }); + + if (!toCreate.length && !toRemove.length && !orphanAppand.length) + return; + + var wasOpen = startUpdate(node); + node.children = null; + + // Fill Parent + toCreate.forEach(function(stat) { + createNode(parentPath + stat.name, stat, null, true); + }); + + toRemove.forEach(function(name) { + var currentNode = existing[name]; + delete existing[name]; + emit("remove", { + path: parentPath + name, + node: currentNode, + parent: node + }); + }); emit("readdir", { path : e.path, parent : node, orphan: orphan }); endUpdate(node, wasOpen); - toAppend.forEach(function(path) { + orphanAppand.forEach(function(path) { emit("orphan-append", {path: path}); }); } fs.on("afterReaddir", onreaddir, plugin); function onstat(e) { - var stat; + if (e.error) return; - if (!e.error) { - // update cache - var there = true; - var node = findNode(e.path); - var parent = findNode(dirname(e.path)); - - if (!showHidden && isFileHidden(e.path)) - return; + // update cache + var stat = e.result[1]; + + var there = true; + var node = findNode(e.path); + var parent = findNode(dirname(e.path)); + + if (!showHidden && isFileHidden(e.path)) + return; - if (!node) { - if (!parent) - return; - there = false; + if (!node) { + if (!parent) + return; + there = false; + } + + if (there != !!stat) { + if (there) { + if (!node.link) + deleteNode(node); } - - if (there != !!e.result[1]) { - if (there) { - if (!node.link) - deleteNode(node); - } - else { - stat = e.result[1]; - if (typeof stat != "object") - stat = null; - createNode(e.path, stat); - } - } - else if (there) { - stat = e.result[1]; + else { if (typeof stat != "object") stat = null; - createNode(e.path, stat, node); + createNode(e.path, stat); } } + else if (there) { + if (typeof stat != "object") + stat = null; + if (!stat && node) + return; + if (stat && node) + updateNodeStat(e.path, stat, node); + else + createNode(e.path, stat, node); + } } fs.on("afterStat", onstat, plugin); fs.on("afterReadFile", function(e) { @@ -518,14 +540,8 @@ define(function(require, exports, module) { updateNode = orphans[path]; delete orphans[path]; } - var original_stat; - if (stat && stat.link) { - original_stat = stat; - stat = stat.linkStat; - } var parts = path.split("/"); - var name = parts[parts.length - 1]; var node = model.root.map[parts[0] == "~" ? "~" : ""]; if (!node) { node = orphans[parts[0]]; @@ -544,7 +560,7 @@ define(function(require, exports, module) { var map = node.map; if (!map) { - map = node.map = {}; + map = node.map = Object.create(null); } parent = node; node = map[p]; @@ -571,8 +587,32 @@ define(function(require, exports, module) { node = {label: parts[parts.length - 1], path: path}; orphans[path] = node; } + + updateNodeStat(path, stat, node); + + node.children = null; + + if (!updating) { + if (!modified.length) + modified.push(parent); + var wasOpen = startUpdate(modified[0]); + modified.forEach(function(n) { + if (n != model.root) + n.children = null; + }); + endUpdate(modified[0], wasOpen); + } + model._signal("createNode", node); + return node; + } + + function updateNodeStat(path, stat, node) { node.path = path; - + var original_stat; + if (stat && stat.link) { + original_stat = stat; + stat = stat.linkStat; + } if (stat) { var isFolder = stat && /(directory|folder)$/.test(stat.mime); if (isFolder) { @@ -596,25 +636,13 @@ define(function(require, exports, module) { delete node.isFolder; } - if (node.isFolder && !node.map) - node.map = {}; - else if (!node.isFolder && node.map) + if (node.isFolder && !node.map) { + node.map = Object.create(null); + node.children = null; + } else if (!node.isFolder && node.map) { delete node.map; - - node.children = null; - - if (!updating) { - if (!modified.length) - modified.push(parent); - var wasOpen = startUpdate(modified[0]); - modified.forEach(function(n) { - if (n != model.root) - n.children = null; - }); - endUpdate(modified[0], wasOpen); + node.children = null; } - model._signal("createNode", node); - return node; } function deleteNode(node, silent) { @@ -677,7 +705,7 @@ define(function(require, exports, module) { map: {} }; var root = {}; - root.map = {}; + root.map = Object.create(null); root.map[""] = model.projectDir; model.setRoot(root); // fs.readdir("/", function(){});