1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
3 : * ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Oracle Corporation code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Oracle Corporation
20 : * Portions created by the Initial Developer are Copyright (C) 2011
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Taras Glek <tglek@mozilla.com>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either the GNU General Public License Version 2 or later (the "GPL"), or
28 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #include <string.h>
41 : #include "mozilla/Telemetry.h"
42 : #include "sqlite3.h"
43 : #include "nsThreadUtils.h"
44 : #include "mozilla/Util.h"
45 :
46 : namespace {
47 :
48 : using namespace mozilla;
49 :
50 : struct Histograms {
51 : const char *name;
52 : const Telemetry::ID readB;
53 : const Telemetry::ID writeB;
54 : const Telemetry::ID readMS;
55 : const Telemetry::ID writeMS;
56 : const Telemetry::ID syncMS;
57 : };
58 :
59 : #define SQLITE_TELEMETRY(FILENAME, HGRAM) \
60 : { FILENAME, \
61 : Telemetry::MOZ_SQLITE_ ## HGRAM ## _READ_B, \
62 : Telemetry::MOZ_SQLITE_ ## HGRAM ## _WRITE_B, \
63 : Telemetry::MOZ_SQLITE_ ## HGRAM ## _READ_MS, \
64 : Telemetry::MOZ_SQLITE_ ## HGRAM ## _WRITE_MS, \
65 : Telemetry::MOZ_SQLITE_ ## HGRAM ## _SYNC_MS \
66 : }
67 :
68 : Histograms gHistograms[] = {
69 : SQLITE_TELEMETRY("places.sqlite", PLACES),
70 : SQLITE_TELEMETRY("urlclassifier3.sqlite", URLCLASSIFIER),
71 : SQLITE_TELEMETRY("cookies.sqlite", COOKIES),
72 : SQLITE_TELEMETRY("webappsstore.sqlite", WEBAPPS),
73 : SQLITE_TELEMETRY(NULL, OTHER)
74 : };
75 : #undef SQLITE_TELEMETRY
76 :
77 : /** RAII class for measuring how long io takes on/off main thread
78 : */
79 : class IOThreadAutoTimer {
80 : public:
81 : /**
82 : * IOThreadAutoTimer measures time spent in IO. Additionally it
83 : * automatically determines whether IO is happening on the main
84 : * thread and picks an appropriate histogram.
85 : *
86 : * @param id takes a telemetry histogram id. The id+1 must be an
87 : * equivalent histogram for the main thread. Eg, MOZ_SQLITE_OPEN_MS
88 : * is followed by MOZ_SQLITE_OPEN_MAIN_THREAD_MS.
89 : */
90 509052 : IOThreadAutoTimer(Telemetry::ID id)
91 : : start(TimeStamp::Now()),
92 509052 : id(id)
93 : {
94 509052 : }
95 :
96 509052 : ~IOThreadAutoTimer() {
97 509052 : PRUint32 mainThread = NS_IsMainThread() ? 1 : 0;
98 : Telemetry::AccumulateTimeDelta(static_cast<Telemetry::ID>(id + mainThread),
99 509052 : start);
100 509052 : }
101 :
102 : private:
103 : const TimeStamp start;
104 : const Telemetry::ID id;
105 : };
106 :
107 : struct telemetry_file {
108 : sqlite3_file base; // Base class. Must be first
109 : Histograms *histograms; // histograms pertaining to this file
110 : sqlite3_file pReal[1]; // This contains the vfs that actually does work
111 : };
112 :
113 : /*
114 : ** Close a telemetry_file.
115 : */
116 : int
117 11040 : xClose(sqlite3_file *pFile)
118 : {
119 11040 : telemetry_file *p = (telemetry_file *)pFile;
120 : int rc;
121 11040 : rc = p->pReal->pMethods->xClose(p->pReal);
122 11040 : if( rc==SQLITE_OK ){
123 11040 : delete p->base.pMethods;
124 11040 : p->base.pMethods = NULL;
125 : }
126 11040 : return rc;
127 : }
128 :
129 : /*
130 : ** Read data from a telemetry_file.
131 : */
132 : int
133 78549 : xRead(sqlite3_file *pFile, void *zBuf, int iAmt, sqlite_int64 iOfst)
134 : {
135 78549 : telemetry_file *p = (telemetry_file *)pFile;
136 157098 : IOThreadAutoTimer ioTimer(p->histograms->readMS);
137 : int rc;
138 78549 : rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
139 : // sqlite likes to read from empty files, this is normal, ignore it.
140 78549 : if (rc != SQLITE_IOERR_SHORT_READ)
141 71909 : Telemetry::Accumulate(p->histograms->readB, rc == SQLITE_OK ? iAmt : 0);
142 78549 : return rc;
143 : }
144 :
145 : /*
146 : ** Write data to a telemetry_file.
147 : */
148 : int
149 384007 : xWrite(sqlite3_file *pFile, const void *zBuf, int iAmt, sqlite_int64 iOfst)
150 : {
151 384007 : telemetry_file *p = (telemetry_file *)pFile;
152 768014 : IOThreadAutoTimer ioTimer(p->histograms->writeMS);
153 : int rc;
154 384007 : rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst);
155 384007 : Telemetry::Accumulate(p->histograms->writeB, rc == SQLITE_OK ? iAmt : 0);
156 384007 : return rc;
157 : }
158 :
159 : /*
160 : ** Truncate a telemetry_file.
161 : */
162 : int
163 7695 : xTruncate(sqlite3_file *pFile, sqlite_int64 size)
164 : {
165 15390 : IOThreadAutoTimer ioTimer(Telemetry::MOZ_SQLITE_TRUNCATE_MS);
166 7695 : telemetry_file *p = (telemetry_file *)pFile;
167 : int rc;
168 15390 : Telemetry::AutoTimer<Telemetry::MOZ_SQLITE_TRUNCATE_MS> timer;
169 7695 : rc = p->pReal->pMethods->xTruncate(p->pReal, size);
170 7695 : return rc;
171 : }
172 :
173 : /*
174 : ** Sync a telemetry_file.
175 : */
176 : int
177 27757 : xSync(sqlite3_file *pFile, int flags)
178 : {
179 27757 : telemetry_file *p = (telemetry_file *)pFile;
180 55514 : IOThreadAutoTimer ioTimer(p->histograms->syncMS);
181 27757 : return p->pReal->pMethods->xSync(p->pReal, flags);
182 : }
183 :
184 : /*
185 : ** Return the current file-size of a telemetry_file.
186 : */
187 : int
188 55651 : xFileSize(sqlite3_file *pFile, sqlite_int64 *pSize)
189 : {
190 55651 : telemetry_file *p = (telemetry_file *)pFile;
191 : int rc;
192 55651 : rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
193 55651 : return rc;
194 : }
195 :
196 : /*
197 : ** Lock a telemetry_file.
198 : */
199 : int
200 31534 : xLock(sqlite3_file *pFile, int eLock)
201 : {
202 31534 : telemetry_file *p = (telemetry_file *)pFile;
203 : int rc;
204 31534 : rc = p->pReal->pMethods->xLock(p->pReal, eLock);
205 31534 : return rc;
206 : }
207 :
208 : /*
209 : ** Unlock a telemetry_file.
210 : */
211 : int
212 25243 : xUnlock(sqlite3_file *pFile, int eLock)
213 : {
214 25243 : telemetry_file *p = (telemetry_file *)pFile;
215 : int rc;
216 25243 : rc = p->pReal->pMethods->xUnlock(p->pReal, eLock);
217 25243 : return rc;
218 : }
219 :
220 : /*
221 : ** Check if another file-handle holds a RESERVED lock on a telemetry_file.
222 : */
223 : int
224 0 : xCheckReservedLock(sqlite3_file *pFile, int *pResOut)
225 : {
226 0 : telemetry_file *p = (telemetry_file *)pFile;
227 0 : int rc = p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut);
228 0 : return rc;
229 : }
230 :
231 : /*
232 : ** File control method. For custom operations on a telemetry_file.
233 : */
234 : int
235 6080 : xFileControl(sqlite3_file *pFile, int op, void *pArg)
236 : {
237 6080 : telemetry_file *p = (telemetry_file *)pFile;
238 6080 : int rc = p->pReal->pMethods->xFileControl(p->pReal, op, pArg);
239 6080 : return rc;
240 : }
241 :
242 : /*
243 : ** Return the sector-size in bytes for a telemetry_file.
244 : */
245 : int
246 0 : xSectorSize(sqlite3_file *pFile)
247 : {
248 0 : telemetry_file *p = (telemetry_file *)pFile;
249 : int rc;
250 0 : rc = p->pReal->pMethods->xSectorSize(p->pReal);
251 0 : return rc;
252 : }
253 :
254 : /*
255 : ** Return the device characteristic flags supported by a telemetry_file.
256 : */
257 : int
258 37131 : xDeviceCharacteristics(sqlite3_file *pFile)
259 : {
260 37131 : telemetry_file *p = (telemetry_file *)pFile;
261 : int rc;
262 37131 : rc = p->pReal->pMethods->xDeviceCharacteristics(p->pReal);
263 37131 : return rc;
264 : }
265 :
266 : /*
267 : ** Shared-memory operations.
268 : */
269 : int
270 237317 : xShmLock(sqlite3_file *pFile, int ofst, int n, int flags)
271 : {
272 237317 : telemetry_file *p = (telemetry_file *)pFile;
273 237317 : return p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags);
274 : }
275 :
276 : int
277 779 : xShmMap(sqlite3_file *pFile, int iRegion, int szRegion, int isWrite, void volatile **pp)
278 : {
279 779 : telemetry_file *p = (telemetry_file *)pFile;
280 : int rc;
281 779 : rc = p->pReal->pMethods->xShmMap(p->pReal, iRegion, szRegion, isWrite, pp);
282 779 : return rc;
283 : }
284 :
285 : void
286 121778 : xShmBarrier(sqlite3_file *pFile){
287 121778 : telemetry_file *p = (telemetry_file *)pFile;
288 121778 : p->pReal->pMethods->xShmBarrier(p->pReal);
289 121778 : }
290 :
291 : int
292 426 : xShmUnmap(sqlite3_file *pFile, int delFlag){
293 426 : telemetry_file *p = (telemetry_file *)pFile;
294 : int rc;
295 426 : rc = p->pReal->pMethods->xShmUnmap(p->pReal, delFlag);
296 426 : return rc;
297 : }
298 :
299 : int
300 11044 : xOpen(sqlite3_vfs* vfs, const char *zName, sqlite3_file* pFile,
301 : int flags, int *pOutFlags)
302 : {
303 22088 : IOThreadAutoTimer ioTimer(Telemetry::MOZ_SQLITE_OPEN_MS);
304 22088 : Telemetry::AutoTimer<Telemetry::MOZ_SQLITE_OPEN_MS> timer;
305 11044 : sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
306 : int rc;
307 11044 : telemetry_file *p = (telemetry_file *)pFile;
308 11044 : Histograms *h = NULL;
309 : // check if the filename is one we are probing for
310 46702 : for(size_t i = 0;i < sizeof(gHistograms)/sizeof(gHistograms[0]);i++) {
311 46702 : h = &gHistograms[i];
312 : // last probe is the fallback probe
313 46702 : if (!h->name)
314 7970 : break;
315 38732 : if (!zName)
316 1644 : continue;
317 37088 : const char *match = strstr(zName, h->name);
318 37088 : if (!match)
319 34010 : continue;
320 3078 : char c = match[strlen(h->name)];
321 : // include -wal/-journal too
322 3078 : if (!c || c == '-')
323 3074 : break;
324 : }
325 11044 : p->histograms = h;
326 11044 : rc = orig_vfs->xOpen(orig_vfs, zName, p->pReal, flags, pOutFlags);
327 11044 : if( rc != SQLITE_OK )
328 4 : return rc;
329 11040 : if( p->pReal->pMethods ){
330 11040 : sqlite3_io_methods *pNew = new sqlite3_io_methods;
331 11040 : const sqlite3_io_methods *pSub = p->pReal->pMethods;
332 11040 : memset(pNew, 0, sizeof(*pNew));
333 11040 : pNew->iVersion = pSub->iVersion;
334 11040 : pNew->xClose = xClose;
335 11040 : pNew->xRead = xRead;
336 11040 : pNew->xWrite = xWrite;
337 11040 : pNew->xTruncate = xTruncate;
338 11040 : pNew->xSync = xSync;
339 11040 : pNew->xFileSize = xFileSize;
340 11040 : pNew->xLock = xLock;
341 11040 : pNew->xUnlock = xUnlock;
342 11040 : pNew->xCheckReservedLock = xCheckReservedLock;
343 11040 : pNew->xFileControl = xFileControl;
344 11040 : pNew->xSectorSize = xSectorSize;
345 11040 : pNew->xDeviceCharacteristics = xDeviceCharacteristics;
346 11040 : if( pNew->iVersion>=2 ){
347 3052 : pNew->xShmMap = pSub->xShmMap ? xShmMap : 0;
348 3052 : pNew->xShmLock = pSub->xShmLock ? xShmLock : 0;
349 3052 : pNew->xShmBarrier = pSub->xShmBarrier ? xShmBarrier : 0;
350 3052 : pNew->xShmUnmap = pSub->xShmUnmap ? xShmUnmap : 0;
351 : }
352 11040 : pFile->pMethods = pNew;
353 : }
354 11040 : return rc;
355 : }
356 :
357 : int
358 10941 : xDelete(sqlite3_vfs* vfs, const char *zName, int syncDir)
359 : {
360 10941 : sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
361 10941 : return orig_vfs->xDelete(orig_vfs, zName, syncDir);
362 : }
363 :
364 : int
365 28865 : xAccess(sqlite3_vfs *vfs, const char *zName, int flags, int *pResOut)
366 : {
367 28865 : sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
368 28865 : return orig_vfs->xAccess(orig_vfs, zName, flags, pResOut);
369 : }
370 :
371 : int
372 4512 : xFullPathname(sqlite3_vfs *vfs, const char *zName, int nOut, char *zOut)
373 : {
374 4512 : sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
375 4512 : return orig_vfs->xFullPathname(orig_vfs, zName, nOut, zOut);
376 : }
377 :
378 : void*
379 0 : xDlOpen(sqlite3_vfs *vfs, const char *zFilename)
380 : {
381 0 : sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
382 0 : return orig_vfs->xDlOpen(orig_vfs, zFilename);
383 : }
384 :
385 : void
386 0 : xDlError(sqlite3_vfs *vfs, int nByte, char *zErrMsg)
387 : {
388 0 : sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
389 0 : orig_vfs->xDlError(orig_vfs, nByte, zErrMsg);
390 0 : }
391 :
392 : void
393 0 : (*xDlSym(sqlite3_vfs *vfs, void *pHdle, const char *zSym))(void){
394 0 : sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
395 0 : return orig_vfs->xDlSym(orig_vfs, pHdle, zSym);
396 : }
397 :
398 : void
399 0 : xDlClose(sqlite3_vfs *vfs, void *pHandle)
400 : {
401 0 : sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
402 0 : orig_vfs->xDlClose(orig_vfs, pHandle);
403 0 : }
404 :
405 : int
406 689 : xRandomness(sqlite3_vfs *vfs, int nByte, char *zOut)
407 : {
408 689 : sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
409 689 : return orig_vfs->xRandomness(orig_vfs, nByte, zOut);
410 : }
411 :
412 : int
413 0 : xSleep(sqlite3_vfs *vfs, int microseconds)
414 : {
415 0 : sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
416 0 : return orig_vfs->xSleep(orig_vfs, microseconds);
417 : }
418 :
419 : int
420 0 : xCurrentTime(sqlite3_vfs *vfs, double *prNow)
421 : {
422 0 : sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
423 0 : return orig_vfs->xCurrentTime(orig_vfs, prNow);
424 : }
425 :
426 : int
427 0 : xGetLastError(sqlite3_vfs *vfs, int nBuf, char *zBuf)
428 : {
429 0 : sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
430 0 : return orig_vfs->xGetLastError(orig_vfs, nBuf, zBuf);
431 : }
432 :
433 : int
434 10655 : xCurrentTimeInt64(sqlite3_vfs *vfs, sqlite3_int64 *piNow)
435 : {
436 10655 : sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
437 10655 : return orig_vfs->xCurrentTimeInt64(orig_vfs, piNow);
438 : }
439 :
440 : static
441 : int
442 0 : xSetSystemCall(sqlite3_vfs *vfs, const char *zName, sqlite3_syscall_ptr pFunc)
443 : {
444 0 : sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
445 0 : return orig_vfs->xSetSystemCall(orig_vfs, zName, pFunc);
446 : }
447 :
448 : static
449 : sqlite3_syscall_ptr
450 0 : xGetSystemCall(sqlite3_vfs *vfs, const char *zName)
451 : {
452 0 : sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
453 0 : return orig_vfs->xGetSystemCall(orig_vfs, zName);
454 : }
455 :
456 : static
457 : const char *
458 0 : xNextSystemCall(sqlite3_vfs *vfs, const char *zName)
459 : {
460 0 : sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
461 0 : return orig_vfs->xNextSystemCall(orig_vfs, zName);
462 : }
463 :
464 : }
465 :
466 : namespace mozilla {
467 : namespace storage {
468 :
469 803 : sqlite3_vfs* ConstructTelemetryVFS()
470 : {
471 : #if defined(XP_WIN)
472 : #define EXPECTED_VFS "win32"
473 : #else
474 : #define EXPECTED_VFS "unix"
475 : #endif
476 :
477 803 : sqlite3_vfs *vfs = sqlite3_vfs_find(NULL);
478 803 : const bool expected_vfs = vfs->zName && !strcmp(vfs->zName, EXPECTED_VFS);
479 803 : if (!expected_vfs) {
480 0 : return NULL;
481 : }
482 :
483 803 : sqlite3_vfs *tvfs = new ::sqlite3_vfs;
484 803 : memset(tvfs, 0, sizeof(::sqlite3_vfs));
485 803 : tvfs->iVersion = 3;
486 : // If the SQLite VFS version is updated, this shim must be updated as well.
487 803 : MOZ_ASSERT(vfs->iVersion == tvfs->iVersion);
488 803 : tvfs->szOsFile = sizeof(telemetry_file) - sizeof(sqlite3_file) + vfs->szOsFile;
489 803 : tvfs->mxPathname = vfs->mxPathname;
490 803 : tvfs->zName = "telemetry-vfs";
491 803 : tvfs->pAppData = vfs;
492 803 : tvfs->xOpen = xOpen;
493 803 : tvfs->xDelete = xDelete;
494 803 : tvfs->xAccess = xAccess;
495 803 : tvfs->xFullPathname = xFullPathname;
496 803 : tvfs->xDlOpen = xDlOpen;
497 803 : tvfs->xDlError = xDlError;
498 803 : tvfs->xDlSym = xDlSym;
499 803 : tvfs->xDlClose = xDlClose;
500 803 : tvfs->xRandomness = xRandomness;
501 803 : tvfs->xSleep = xSleep;
502 803 : tvfs->xCurrentTime = xCurrentTime;
503 803 : tvfs->xGetLastError = xGetLastError;
504 : // Added in version 2.
505 803 : tvfs->xCurrentTimeInt64 = xCurrentTimeInt64;
506 : // Added in version 3.
507 803 : tvfs->xSetSystemCall = xSetSystemCall;
508 803 : tvfs->xGetSystemCall = xGetSystemCall;
509 803 : tvfs->xNextSystemCall = xNextSystemCall;
510 :
511 803 : return tvfs;
512 : }
513 :
514 : }
515 : }
|