Skip to content

Commit 02c929b

Browse files
committed
Merge pull request #38 from 10gen/INT-141_collection-stats
Int 141 collection stats
2 parents 5280880 + b39a245 commit 02c929b

File tree

8 files changed

+273
-75
lines changed

8 files changed

+273
-75
lines changed

scout-brain/lib/models/_index.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
1-
// @todo: When schema for Index finalized in server,
2-
// make them real props here.
31
module.exports = require('ampersand-model').extend({
4-
extraProperties: 'allow'
2+
idAttribute: '_id',
3+
props: {
4+
key: 'object',
5+
name: 'string',
6+
ns: 'string',
7+
v: 'number',
8+
size: 'number'
9+
},
10+
derived: {
11+
_id: {
12+
deps: ['name', 'ns'],
13+
fn: function() {
14+
return this.ns + '.' + this.name;
15+
}
16+
}
17+
}
518
});
Lines changed: 100 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,7 @@
1-
var AmpersandState = require('ampersand-state');
21
var AmpersandModel = require('ampersand-model');
3-
var AmpersandCollection = require('ampersand-collection');
4-
var debug = require('debug')('scout-brain:models:collection');
5-
2+
var _ = require('underscore');
63
var types = require('../types');
7-
8-
// @todo: When schema for Index finalized in server,
9-
// make them real props here.
10-
var CollectionIndex = AmpersandState.extend({
11-
extraProperties: 'allow'
12-
});
13-
14-
var CollectionIndexes = AmpersandCollection.extend({
15-
model: CollectionIndex
16-
});
4+
var IndexCollection = require('./_index-collection');
175

186
var Collection = AmpersandModel.extend({
197
idAttribute: '_id',
@@ -23,7 +11,6 @@ var Collection = AmpersandModel.extend({
2311
required: true
2412
},
2513
database: 'string',
26-
index_sizes: 'number',
2714
document_count: 'number',
2815
document_size: 'number',
2916
storage_size: 'number',
@@ -32,31 +19,118 @@ var Collection = AmpersandModel.extend({
3219
padding_factor: 'number',
3320
extent_count: 'number',
3421
extent_last_size: 'number',
22+
/**
23+
* http://docs.mongodb.org/manual/reference/command/collStats/#collStats.userFlags
24+
*/
3525
flags_user: 'number',
36-
flags_system: 'number'
26+
flags_system: 'number',
27+
/**
28+
* Is this a capped collection?
29+
*/
30+
capped: {
31+
type: 'boolean',
32+
default: false
33+
},
34+
/**
35+
* Is this collection using power of 2 allocation?
36+
*
37+
* http://docs.mongodb.org/manual/core/storage/#power-of-2-allocation
38+
*/
39+
power_of_two: {
40+
type: 'boolean',
41+
default: true
42+
},
43+
/**
44+
* The total size in memory of all records in a collection. This value does
45+
* not include the record header, which is 16 bytes per record, but does
46+
* include the record’s padding. Additionally size does not include the
47+
* size of any indexes associated with the collection, which the
48+
* totalIndexSize field reports..
49+
*
50+
* http://docs.mongodb.org/manual/reference/command/collStats/#collStats.size
51+
*/
52+
size: 'number',
53+
/**
54+
* New in version 3.0.0.
55+
*
56+
* A document that reports data from the storage engine for each index
57+
* in the collection.
58+
*
59+
* The fields in this document are the names of the indexes, while the
60+
* values themselves are documents that contain statistics for the index
61+
* provided by the storage engine. These statistics are for
62+
* internal diagnostic use.
63+
*
64+
* http://docs.mongodb.org/manual/reference/command/collStats/#collStats.indexDetails
65+
*/
66+
index_details: 'object',
67+
/**
68+
* New in version 3.0.0.
69+
*
70+
* wiredTiger only appears when using the wiredTiger storage engine. This
71+
* document contains data reported directly by the WiredTiger engine and
72+
* other data for internal diagnostic use.
73+
*
74+
* http://docs.mongodb.org/manual/reference/command/collStats/#collStats.wiredTiger
75+
*/
76+
wired_tiger: 'object'
3777
},
38-
// extraProperties: 'reject',
3978
collections: {
40-
indexes: CollectionIndexes
79+
indexes: IndexCollection
4180
},
4281
derived: {
82+
document_size_average: {
83+
deps: ['document_size', 'document_count'],
84+
fn: function() {
85+
if (!this.document_size || !this.document_count) return;
86+
return this.document_size / this.document_count;
87+
}
88+
},
89+
index_size_average: {
90+
deps: ['index_size', 'index_count'],
91+
fn: function() {
92+
if (!this.index_size || !this.index_count) return;
93+
return this.index_size / this.index_count;
94+
}
95+
},
4396
name: {
4497
deps: ['_id'],
4598
fn: function() {
46-
debug('%s -> %j', this._id, types.ns(this._id));
99+
if (!this._id) return undefined;
47100
return types.ns(this._id).collection;
48101
}
49102
},
50103
specialish: {
51-
name: {
52-
deps: ['_id'],
53-
fn: function() {
54-
debug('%s -> %j', this._id, types.ns(this._id));
55-
return types.ns(this._id).specialish;
56-
}
104+
deps: ['_id'],
105+
fn: function() {
106+
if (!this._id) return undefined;
107+
return types.ns(this._id).specialish;
57108
}
58109
}
59-
}
110+
},
111+
parse: function(d) {
112+
// @todo: update scout-server to just do this.
113+
if (d.index_sizes) {
114+
_.each(d.indexes, function(data, name) {
115+
d.indexes[name].size = d.index_sizes[name];
116+
});
117+
}
118+
return d;
119+
},
120+
serialize: function() {
121+
var res = this.getAttributes({
122+
props: true,
123+
derived: true
124+
}, true);
125+
126+
_.each(this._children, function(value, key) {
127+
res[key] = this[key].serialize();
128+
}, this);
129+
_.each(this._collections, function(value, key) {
130+
res[key] = this[key].serialize();
131+
}, this);
132+
return res;
133+
},
60134
});
61135

62136
module.exports = Collection;

scout-server/lib/routes/collection.js

Lines changed: 43 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,21 @@ function getCollectionFeatures(req, fn) {
2424
req.db.command({
2525
collStats: req.ns.collection
2626
}, {
27-
verbose: 1
28-
}, function(err, data) {
29-
if (err) return fn(err);
30-
31-
req.collection_features = {
32-
capped: data.capped,
33-
max: data.max,
34-
size: data.size,
35-
power_of_two: data.userFlags === 1
36-
};
37-
fn(null, req.collection_features);
38-
});
27+
verbose: 1
28+
}, function(err, data) {
29+
if (err) return fn(err);
30+
31+
req.collection_features = {
32+
capped: data.capped,
33+
max_document_count: data.max,
34+
max_document_size: data.maxSize,
35+
size: data.size,
36+
power_of_two: data.userFlags === 1,
37+
index_details: data.indexDetails || {},
38+
wired_tiger: data.wiredTiger || {}
39+
};
40+
fn(null, req.collection_features);
41+
});
3942
}
4043

4144
function getCollectionStats(req, fn) {
@@ -47,33 +50,29 @@ function getCollectionStats(req, fn) {
4750
req.db.command({
4851
collStats: req.ns.collection
4952
}, {
50-
verbose: 1
51-
}, function(err, data) {
52-
if (err) return fn(err);
53-
54-
req.collection_stats = {
55-
index_sizes: data.indexSizes,
56-
document_count: data.count,
57-
document_size: data.size,
58-
storage_size: data.storageSize,
59-
index_count: data.nindexes,
60-
index_size: data.totalIndexSize,
61-
padding_factor: data.paddingFactor,
62-
extent_count: data.numExtents,
63-
extent_last_size: data.lastExtentSize,
64-
flags_user: data.userFlags,
65-
flags_system: data.systemFlags
66-
};
67-
fn(null, req.collection_stats);
68-
});
53+
verbose: 1
54+
}, function(err, data) {
55+
if (err) return fn(err);
56+
57+
req.collection_stats = {
58+
index_sizes: data.indexSizes,
59+
document_count: data.count,
60+
document_size: data.size,
61+
storage_size: data.storageSize,
62+
index_count: data.nindexes,
63+
index_size: data.totalIndexSize,
64+
padding_factor: data.paddingFactor,
65+
extent_count: data.numExtents,
66+
extent_last_size: data.lastExtentSize,
67+
flags_user: data.userFlags,
68+
flags_system: data.systemFlags
69+
};
70+
fn(null, req.collection_stats);
71+
});
6972
}
7073

7174
function getCollectionIndexes(req, fn) {
72-
req.db.collection('system.indexes')
73-
.find({
74-
ns: req.ns.toString()
75-
})
76-
.toArray(fn);
75+
req.db.collection(req.ns.collection).listIndexes().toArray(fn);
7776
}
7877

7978
// @todo: Move to scount-sync.collection.fetch().
@@ -128,14 +127,14 @@ module.exports = {
128127
query: req.json('query'),
129128
size: req.int('size', 5)
130129
})
131-
.pipe(_idToDocument(req.db, req.ns.collection, {
132-
fields: req.json('fields')
133-
}))
134-
.pipe(EJSON.createStringifyStream())
135-
.pipe(setHeaders(req, res, {
136-
'content-type': 'application/json'
137-
}))
138-
.pipe(res);
130+
.pipe(_idToDocument(req.db, req.ns.collection, {
131+
fields: req.json('fields')
132+
}))
133+
.pipe(EJSON.createStringifyStream())
134+
.pipe(setHeaders(req, res, {
135+
'content-type': 'application/json'
136+
}))
137+
.pipe(res);
139138

140139
},
141140
bulk: function(req, res, next) {
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
div.row.hidden
2+
.col-md-6
3+
dl.dl-horizontal
4+
dt # documents
5+
dd(data-hook='document_count')
6+
dt total document size
7+
dd(data-hook='document_size')
8+
dt average document size
9+
dd(data-hook='document_size_average')
10+
.col-md-6
11+
dl.dl-horizontal
12+
dt # indexes
13+
dd(data-hook='index_count')
14+
dt total index size
15+
dd(data-hook='index_size')
16+
dt average index size
17+
dd(data-hook='index_size_average')
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
var AmpersandView = require('ampersand-view');
2+
var numeral = require('numeral');
3+
4+
var CollectionStatsView = AmpersandView.extend({
5+
bindings: {
6+
'model._id': {
7+
hook: 'name'
8+
},
9+
document_count: {
10+
hook: 'document_count'
11+
},
12+
document_size: {
13+
hook: 'document_size'
14+
},
15+
document_size_average: {
16+
hook: 'document_size_average'
17+
},
18+
index_count: {
19+
hook: 'index_count'
20+
},
21+
index_size: {
22+
hook: 'index_size'
23+
},
24+
index_size_average: {
25+
hook: 'index_size_average'
26+
},
27+
},
28+
derived: {
29+
document_count: {
30+
deps: ['model.document_count'],
31+
fn: function() {
32+
return numeral(this.model.document_count).format('0.0a');
33+
}
34+
},
35+
document_size: {
36+
deps: ['model.document_size'],
37+
fn: function() {
38+
return numeral(this.model.document_size).format('0.0b');
39+
}
40+
},
41+
document_size_average: {
42+
deps: ['model.document_size_average'],
43+
fn: function() {
44+
return numeral(this.model.document_size_average).format('0.0b');
45+
}
46+
},
47+
index_count: {
48+
deps: ['model.index_count'],
49+
fn: function() {
50+
return numeral(this.model.index_count).format('0.0a');
51+
}
52+
},
53+
index_size: {
54+
deps: ['model.index_size'],
55+
fn: function() {
56+
return numeral(this.model.index_size).format('0.0b');
57+
}
58+
},
59+
index_size_average: {
60+
deps: ['model.index_size_average'],
61+
fn: function() {
62+
return numeral(this.model.index_size_average).format('0.0b');
63+
}
64+
}
65+
},
66+
template: require('./index.jade')
67+
});
68+
69+
module.exports = CollectionStatsView;

scout-ui/src/home/collection.jade

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@
22
.panel
33
.panel-heading
44
h3(data-hook='name')
5+
div(data-hook='stats-container')
56
.panel-body
67
div(data-hook='fields-container')

0 commit comments

Comments
 (0)