From 9836cf571708a82396218957cacb3ed1ed468d05 Mon Sep 17 00:00:00 2001 From: Daniel Pihlstrom Date: Wed, 3 May 2017 18:26:31 -0400 Subject: [PATCH] lib: lazy instantiation of fs.Stats dates The method used has code duplication but is the most performant PR-URL: https://github.com/nodejs/node/pull/12818 Reviewed-By: Anna Henningsen Reviewed-By: James M Snell Reviewed-By: Refael Ackermann --- lib/fs.js | 74 +++++++++++++++++++++++++++++++++-- test/parallel/test-fs-stat.js | 22 +++++++++++ 2 files changed, 92 insertions(+), 4 deletions(-) diff --git a/lib/fs.js b/lib/fs.js index de5d6dcfb0fcbf..c50788a03dbd68 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -196,13 +196,79 @@ function Stats( this.ino = ino; this.size = size; this.blocks = blocks; - this.atime = new Date(atim_msec); - this.mtime = new Date(mtim_msec); - this.ctime = new Date(ctim_msec); - this.birthtime = new Date(birthtim_msec); + this._atim_msec = atim_msec; + this._mtim_msec = mtim_msec; + this._ctim_msec = ctim_msec; + this._birthtim_msec = birthtim_msec; } fs.Stats = Stats; +// defining the properties in this fashion (explicitly with no loop or factory) +// has been shown to be the most performant on V8 contemp. +// Ref: https://github.com/nodejs/node/pull/12818 +Object.defineProperties(Stats.prototype, { + atime: { + configurable: true, + enumerable: true, + get() { + return this._atime !== undefined ? + this._atime : + (this._atime = new Date(this._atim_msec + 0.5)); + }, + set(value) { return this._atime = value; } + }, + mtime: { + configurable: true, + enumerable: true, + get() { + return this._mtime !== undefined ? + this._mtime : + (this._mtime = new Date(this._mtim_msec + 0.5)); + }, + set(value) { return this._mtime = value; } + }, + ctime: { + configurable: true, + enumerable: true, + get() { + return this._ctime !== undefined ? + this._ctime : + (this._ctime = new Date(this._ctim_msec + 0.5)); + }, + set(value) { return this._ctime = value; } + }, + birthtime: { + configurable: true, + enumerable: true, + get() { + return this._birthtime !== undefined ? + this._birthtime : + (this._birthtime = new Date(this._birthtim_msec + 0.5)); + }, + set(value) { return this._birthtime = value; } + }, +}); + +Stats.prototype.toJSON = function toJSON() { + return { + dev: this.dev, + mode: this.mode, + nlink: this.nlink, + uid: this.uid, + gid: this.gid, + rdev: this.rdev, + blksize: this.blksize, + ino: this.ino, + size: this.size, + blocks: this.blocks, + atime: this.atime, + ctime: this.ctime, + mtime: this.mtime, + birthtime: this.birthtime + }; +}; + + Stats.prototype._checkModeProperty = function(property) { return ((this.mode & S_IFMT) === property); }; diff --git a/test/parallel/test-fs-stat.js b/test/parallel/test-fs-stat.js index 6ed27806b9343c..0769f79f1c502d 100644 --- a/test/parallel/test-fs-stat.js +++ b/test/parallel/test-fs-stat.js @@ -98,5 +98,27 @@ fs.stat(__filename, common.mustCall(function(err, s) { console.log(`isSymbolicLink: ${JSON.stringify(s.isSymbolicLink())}`); assert.strictEqual(false, s.isSymbolicLink()); + assert.ok(s.atime instanceof Date); assert.ok(s.mtime instanceof Date); + assert.ok(s.ctime instanceof Date); + assert.ok(s.birthtime instanceof Date); +})); + +fs.stat(__filename, common.mustCall(function(err, s) { + const json = JSON.parse(JSON.stringify(s)); + const keys = [ + 'dev', 'mode', 'nlink', 'uid', + 'gid', 'rdev', 'ino', + 'size', 'atime', 'mtime', + 'ctime', 'birthtime' + ]; + if (!common.isWindows) { + keys.push('blocks', 'blksize'); + } + keys.forEach(function(k) { + assert.ok( + json[k] !== undefined && json[k] !== null, + k + ' should not be null or undefined' + ); + }); }));