UNPKG

7.05 kBJavaScriptView Raw
1//- JavaScript source code
2
3//- defs-mongo.js ~~
4//
5// These definitions are chosen by default in the QM project Makefile.
6//
7// ~~ (c) SRW, 05 Nov 2012
8// ~~ last updated 07 Aug 2014
9
10(function () {
11 'use strict';
12
13 // Pragmas
14
15 /*jshint maxparams: 2, quotmark: single, strict: true */
16
17 /*jslint indent: 4, maxlen: 80, node: true, nomen: true */
18
19 /*properties
20 api, avar_ttl, background, body, box_status, collect_garbage,
21 collection, connect, ensureIndex, error, exp_date, expireAfterSeconds,
22 find, findAndModify, gc_interval, get_avar, get_list, '_id', insert,
23 isWorker, key, length, log, '$lt', mongo, MongoClient, now, on, push,
24 remove, safe, '$set', set_avar, sparse, stream, update, upsert
25 */
26
27 // Declarations
28
29 var cluster, mongo;
30
31 // Definitions
32
33 cluster = require('cluster');
34
35 mongo = require('mongodb').MongoClient;
36
37 // Out-of-scope definitions
38
39 exports.api = function (options) {
40 // This function needs documentation, but as far as connection pooling is
41 // concerned, my strategy is justified by the post on Stack Overflow at
42 // http://stackoverflow.com/a/14464750.
43
44 var collect_garbage, db, get_avar, get_list, set_avar;
45
46 collect_garbage = function () {
47 // This function isn't always needed now that QM uses TTL collections.
48 // Since Mongo guarantees that it will remove outdated documents every
49 // 60 seconds, we only need to remove documents manually if the
50 // `gc_interval` is less than 60 seconds. See Mongo's documentation at
51 // http://docs.mongodb.org/manual/tutorial/expire-data/ for more info.
52 var oldest, query;
53 oldest = new Date(Date.now() - (1000 * options.gc_interval));
54 query = {'exp_date': {'$lt': oldest}};
55 if (options.gc_interval < 60) {
56 db.collection('avars').remove(query, function (err) {
57 // This function needs documentation.
58 if (err !== null) {
59 console.error('Error:', err);
60 return;
61 }
62 console.log('Finished collecting garbage.');
63 return;
64 });
65 }
66 return;
67 };
68
69 get_avar = function (params, callback) {
70 // This function retrieves an avar's representation if it exists, and
71 // it also updates the "expiration date" of the avar in the database
72 // so that data still being used for computations will not be removed.
73 var exp_date, f, query;
74 exp_date = new Date(Date.now() + (1000 * options.avar_ttl));
75 f = function (err, doc) {
76 // This is the callback function for `findAndModify`.
77 if (err !== null) {
78 return callback(err, undefined);
79 }
80 return callback(null, (doc === null) ? undefined : doc.body);
81 };
82 query = {'_id': params[0] + '&' + params[1]};
83 db.collection('avars').findAndModify(query,
84 [], {'$set': {'exp_date': exp_date}}, {'upsert': false}, f);
85 return;
86 };
87
88 get_list = function (params, callback) {
89 // This function needs documentation.
90 var docs, query, stream;
91 docs = [];
92 query = {'box_status': params[0] + '&' + params[1]};
93 stream = db.collection('avars').find(query).stream();
94 stream.on('close', function () {
95 // This function needs documentation.
96 return callback(null, docs);
97 });
98 stream.on('data', function (doc) {
99 // This function needs documentation.
100 docs.push(doc.key);
101 return;
102 });
103 stream.on('error', callback);
104 return;
105 };
106
107 set_avar = function (params, callback) {
108 // This function needs documentation.
109 var exp_date, obj, opts, query;
110 exp_date = new Date(Date.now() + (1000 * options.avar_ttl));
111 if (params.length === 4) {
112 obj = {
113 '_id': params[0] + '&' + params[1],
114 'body': params[3],
115 'box_status': params[0] + '&' + params[2],
116 'exp_date': exp_date,
117 'key': params[1]
118 };
119 } else {
120 obj = {
121 '_id': params[0] + '&' + params[1],
122 'body': params[2],
123 'exp_date': exp_date,
124 'key': params[1]
125 };
126 }
127 opts = {'safe': true, 'upsert': true};
128 query = {'_id': params[0] + '&' + params[1]};
129 db.collection('avars').update(query, obj, opts, callback);
130 return;
131 };
132
133 mongo.connect(options.mongo, function (err, db_handle) {
134 // This function initializes a connection to MongoDB and also creates
135 // a TTL index on the collection.
136 if (err !== null) {
137 throw err;
138 }
139 db = db_handle;
140 if (cluster.isWorker) {
141 return;
142 }
143 db.collection('avars').ensureIndex({'exp_date': 1}, {
144 'expireAfterSeconds': 0
145 }, function (err) {
146 // This function needs documentation.
147 if (err !== null) {
148 throw err;
149 }
150 var f, opts;
151 f = function (err) {
152 // This function needs documentation.
153 if (err !== null) {
154 console.error('Error:', err);
155 }
156 return;
157 };
158 opts = {'background': true, 'sparse': true};
159 db.collection('avars').ensureIndex('box_status', opts, f);
160 console.log('API: MongoDB storage is ready.');
161 return;
162 });
163 return;
164 });
165
166 return {
167 'collect_garbage': collect_garbage,
168 'get_avar': get_avar,
169 'get_list': get_list,
170 'set_avar': set_avar
171 };
172 };
173
174 exports.log = function (options) {
175 // This function needs documentation.
176 var db;
177 mongo.connect(options.mongo, function (err, db_handle) {
178 // This function needs documentation.
179 if (err !== null) {
180 throw err;
181 }
182 db = db_handle;
183 return;
184 });
185 return function (obj) {
186 // This function needs documentation.
187 db.collection('traffic').insert(obj, {'safe': false});
188 return;
189 };
190 };
191
192 // That's all, folks!
193
194 return;
195
196}());
197
198//- vim:set syntax=javascript: