@sap/xsodata
Version:
Expose data from a HANA database as OData V2 service with help of .xsodata files.
165 lines (138 loc) • 4.79 kB
JavaScript
;
function Measurement(name, startImmediately) {
this.name = name || process.hrtime()[1];// if a name is not given, provide the time instance as a unique name
this.timeStart = 0;
this.time = 0;
this.children = [];
if (startImmediately) {
this.counterStart();
}
}
/**
* pushes the current measurement into the global stack and starts the counter
* */
Measurement.prototype.counterStart = function () {
Measurement.stack.push(this);
this.timeStart = process.hrtime();
};
/**
* stops the counter and assigns the time difference to this.time
* - hrtime() returns a tuple [seconds, nanoseconds]
* pops the stack as the current counter(measurement) is not valid anymore
*/
Measurement.prototype.counterStop = function () {
if (this.timeStart === 0) { // the counter did not start
return;
}
this.time = process.hrtime(this.timeStart);
this.time = this.time[0] * 1000000 + Math.round(this.time[1] / 1000);
/* the element to pop is most likely at the top of the stack:
* - if so, spare the linear search
* - if not, must do a linear seach: this happens when using an async iterator, e.g. async.map*/
if (this === Measurement.getRunningMeasurement()) {
Measurement.stack.pop();
} else {
Measurement.removeFromStack(this);
}
return this.time;
};
Measurement.prototype.newChild = function (name) {
var child = new Measurement(name);
this.children.push(child);
return child;
};
Measurement.prototype.printTime = function () {
console.log('**', this.name, 'took', this.time, 'microSec');
};
/*************************** static members */
Measurement.stack = [];
Measurement.active = false;
Measurement.setActive = function (val) {
Measurement.active = val;
};
Measurement.isActive = function () {
return Measurement.active;
};
/**
* Returns the currently running measurement, which comes at stack's top
* */
Measurement.getRunningMeasurement = function () {
if (Measurement.stack.length === 0) {
// this happens only in testing scripts
return new Measurement('test');
}
return Measurement.stack[Measurement.stack.length - 1];
};
Measurement.removeFromStack = function (measure) {
var index = -1;
// search for the given measurement, based on "name"
Measurement.stack.forEach(function (value, i) {
if (value.name === measure.name) {
index = i;
}
});
// pop (slice 1 element) at the found index
if (index !== -1) {
Measurement.stack.splice(index, 1);
}
return index;
};
Measurement.measureAsync = function (fn, name) {
if (Measurement.isActive()) {
return function (contextOuter, asyncDone) {
// get the parent measurement, within which the current measurement will run (as a child)
// e.g. ODataHandler.processRequest is the parent of all waterfall's functions (e.g. db.connect)
var parent = Measurement.getRunningMeasurement();
var child = parent.newChild(name);
child.counterStart();
fn(contextOuter, function (err, context) {
child.counterStop();
return asyncDone(err, context);
});
};
} else {
return function (contextOuter, asyncDone) {
fn(contextOuter, function (err, context) {
return asyncDone(err, context);
});
};
}
};
Measurement.measureSync = function (fn /** args .., name*/) {
var args = Array.prototype.slice.call(arguments, 1, arguments.length - 1);
var res;
if (Measurement.isActive()) {
var name = arguments[arguments.length - 1];
// <-
var parent = Measurement.getRunningMeasurement();
var child = parent.newChild(name);
child.counterStart();
// =
res = fn.apply(null, args);
// ->
child.counterStop();
} else {
res = fn.apply(null, args);
}
return res;
};
// when the function to be called has a callback
Measurement.measureWithCB = function (fn /** args, .., cb, name */) {
var args = Array.prototype.slice.call(arguments, 1, arguments.length - 2),
cb = arguments[arguments.length - 2];
args = args.concat(wrapCB);
if (Measurement.isActive()) {
var name = arguments[arguments.length - 1];
var parent = Measurement.getRunningMeasurement();
var child = parent.newChild(name);
child.counterStart();
}
return fn.apply(null, args); // the counter implicitly stops
function wrapCB(err, context) {
if (Measurement.isActive()) {
child.counterStop();
}
cb(err, context);
}
};
module.exports = Measurement;