OLD | NEW |
1 // Copyright (c) 2017 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2017 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "sql/vfs_wrapper.h" | 5 #include "sql/vfs_wrapper.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <string> | 8 #include <string> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
11 #include "base/debug/leak_annotations.h" | 11 #include "base/debug/leak_annotations.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/memory/ptr_util.h" | 13 #include "base/memory/ptr_util.h" |
| 14 #include "base/metrics/histogram_macros.h" |
14 #include "base/strings/string_piece.h" | 15 #include "base/strings/string_piece.h" |
15 | 16 |
16 #if defined(OS_MACOSX) && !defined(OS_IOS) | 17 #if defined(OS_MACOSX) && !defined(OS_IOS) |
17 #include <CoreFoundation/CoreFoundation.h> | 18 #include <CoreFoundation/CoreFoundation.h> |
18 #include <CoreServices/CoreServices.h> | 19 #include <CoreServices/CoreServices.h> |
19 | 20 |
20 #include "base/mac/mac_util.h" | 21 #include "base/mac/mac_util.h" |
21 #include "base/mac/scoped_cftyperef.h" | 22 #include "base/mac/scoped_cftyperef.h" |
22 #endif | 23 #endif |
23 | 24 |
24 namespace sql { | 25 namespace sql { |
25 namespace { | 26 namespace { |
26 | 27 |
27 // https://www.sqlite.org/vfs.html - documents the overall VFS system. | 28 // https://www.sqlite.org/vfs.html - documents the overall VFS system. |
28 // | 29 // |
29 // https://www.sqlite.org/c3ref/vfs.html - VFS methods. This code tucks the | 30 // https://www.sqlite.org/c3ref/vfs.html - VFS methods. This code tucks the |
30 // wrapped VFS pointer into the wrapper's pAppData pointer. | 31 // wrapped VFS pointer into the wrapper's pAppData pointer. |
31 // | 32 // |
32 // https://www.sqlite.org/c3ref/file.html - instance of an open file. This code | 33 // https://www.sqlite.org/c3ref/file.html - instance of an open file. This code |
33 // allocates a VfsFile for this, which contains a pointer to the wrapped file. | 34 // allocates a VfsFile for this, which contains a pointer to the wrapped file. |
34 // Idiomatic SQLite would take the wrapped VFS szOsFile and increase it to store | 35 // Idiomatic SQLite would take the wrapped VFS szOsFile and increase it to store |
35 // additional data as a prefix. | 36 // additional data as a prefix. |
36 | 37 |
| 38 // This enum must match the numbering from Sqlite.VfsEvents in histograms.xml. |
| 39 // Do not reorder or remove items, only add new items before VFS_EVENT_MAX. |
| 40 enum VfsEventType { |
| 41 // VFS method xOpen() call. |
| 42 VFS_OPEN = 0, |
| 43 |
| 44 // VFS method xDelete() call. |
| 45 VFS_DELETE, |
| 46 |
| 47 // VFS method xAccess() call. |
| 48 VFS_ACCESS, |
| 49 |
| 50 // VFS method xFullPathname() call. |
| 51 VFS_FULLPATHNAME, |
| 52 |
| 53 // I/O method xClose() call, should balance VFS_OPEN. |
| 54 VFS_IO_CLOSE, |
| 55 |
| 56 // I/O method xRead() call. |
| 57 VFS_IO_READ, |
| 58 |
| 59 // I/O method xWrite() call. |
| 60 VFS_IO_WRITE, |
| 61 |
| 62 // I/O method xTruncate() call. |
| 63 VFS_IO_TRUNCATE, |
| 64 |
| 65 // I/O method xSync() call. |
| 66 VFS_IO_SYNC, |
| 67 |
| 68 // I/O method xFileSize() call. |
| 69 VFS_IO_FILESIZE, |
| 70 |
| 71 // I/O method xFetch() call. This is like xRead(), but when using |
| 72 // memory-mapping. |
| 73 VFS_IO_FETCH, |
| 74 |
| 75 // Add new items before this one, always keep this one at the end. |
| 76 VFS_EVENT_MAX |
| 77 }; |
| 78 |
| 79 // TODO(shess): If the VFS was parameterized, then results could be binned by |
| 80 // database. It would require a separate VFS per database, though the variants |
| 81 // could all use the same VFS functions. |
| 82 void RecordVfsEvent(VfsEventType vfs_event) { |
| 83 UMA_HISTOGRAM_ENUMERATION("Sqlite.Vfs_Events", vfs_event, VFS_EVENT_MAX); |
| 84 } |
| 85 |
37 sqlite3_vfs* GetWrappedVfs(sqlite3_vfs* wrapped_vfs) { | 86 sqlite3_vfs* GetWrappedVfs(sqlite3_vfs* wrapped_vfs) { |
38 return static_cast<sqlite3_vfs*>(wrapped_vfs->pAppData); | 87 return static_cast<sqlite3_vfs*>(wrapped_vfs->pAppData); |
39 } | 88 } |
40 | 89 |
41 // NOTE(shess): This structure is allocated by SQLite using malloc. Do not add | 90 // NOTE(shess): This structure is allocated by SQLite using malloc. Do not add |
42 // C++ objects, they will not be correctly constructed and destructed. Instead, | 91 // C++ objects, they will not be correctly constructed and destructed. Instead, |
43 // manually manage a pointer to a C++ object in Open() and Close(). | 92 // manually manage a pointer to a C++ object in Open() and Close(). |
44 struct VfsFile { | 93 struct VfsFile { |
45 const sqlite3_io_methods* methods; | 94 const sqlite3_io_methods* methods; |
46 sqlite3_file* wrapped_file; | 95 sqlite3_file* wrapped_file; |
47 }; | 96 }; |
48 | 97 |
49 VfsFile* AsVfsFile(sqlite3_file* wrapper_file) { | 98 VfsFile* AsVfsFile(sqlite3_file* wrapper_file) { |
50 return reinterpret_cast<VfsFile*>(wrapper_file); | 99 return reinterpret_cast<VfsFile*>(wrapper_file); |
51 } | 100 } |
52 | 101 |
53 sqlite3_file* GetWrappedFile(sqlite3_file* wrapper_file) { | 102 sqlite3_file* GetWrappedFile(sqlite3_file* wrapper_file) { |
54 return AsVfsFile(wrapper_file)->wrapped_file; | 103 return AsVfsFile(wrapper_file)->wrapped_file; |
55 } | 104 } |
56 | 105 |
57 int Close(sqlite3_file* sqlite_file) | 106 int Close(sqlite3_file* sqlite_file) |
58 { | 107 { |
| 108 RecordVfsEvent(VFS_IO_CLOSE); |
| 109 |
59 VfsFile* file = AsVfsFile(sqlite_file); | 110 VfsFile* file = AsVfsFile(sqlite_file); |
60 | 111 |
61 int r = file->wrapped_file->pMethods->xClose(file->wrapped_file); | 112 int r = file->wrapped_file->pMethods->xClose(file->wrapped_file); |
62 sqlite3_free(file->wrapped_file); | 113 sqlite3_free(file->wrapped_file); |
63 memset(file, '\0', sizeof(*file)); | 114 memset(file, '\0', sizeof(*file)); |
64 return r; | 115 return r; |
65 } | 116 } |
66 | 117 |
67 int Read(sqlite3_file* sqlite_file, void* buf, int amt, sqlite3_int64 ofs) | 118 int Read(sqlite3_file* sqlite_file, void* buf, int amt, sqlite3_int64 ofs) |
68 { | 119 { |
| 120 RecordVfsEvent(VFS_IO_READ); |
| 121 UMA_HISTOGRAM_COUNTS("Sqlite.Vfs_Read", amt); |
| 122 |
69 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); | 123 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); |
70 return wrapped_file->pMethods->xRead(wrapped_file, buf, amt, ofs); | 124 return wrapped_file->pMethods->xRead(wrapped_file, buf, amt, ofs); |
71 } | 125 } |
72 | 126 |
73 int Write(sqlite3_file* sqlite_file, const void* buf, int amt, | 127 int Write(sqlite3_file* sqlite_file, const void* buf, int amt, |
74 sqlite3_int64 ofs) | 128 sqlite3_int64 ofs) |
75 { | 129 { |
| 130 RecordVfsEvent(VFS_IO_WRITE); |
| 131 UMA_HISTOGRAM_COUNTS("Sqlite.Vfs_Write", amt); |
| 132 |
76 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); | 133 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); |
77 return wrapped_file->pMethods->xWrite(wrapped_file, buf, amt, ofs); | 134 return wrapped_file->pMethods->xWrite(wrapped_file, buf, amt, ofs); |
78 } | 135 } |
79 | 136 |
80 int Truncate(sqlite3_file* sqlite_file, sqlite3_int64 size) | 137 int Truncate(sqlite3_file* sqlite_file, sqlite3_int64 size) |
81 { | 138 { |
| 139 RecordVfsEvent(VFS_IO_TRUNCATE); |
| 140 |
82 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); | 141 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); |
83 return wrapped_file->pMethods->xTruncate(wrapped_file, size); | 142 return wrapped_file->pMethods->xTruncate(wrapped_file, size); |
84 } | 143 } |
85 | 144 |
86 int Sync(sqlite3_file* sqlite_file, int flags) | 145 int Sync(sqlite3_file* sqlite_file, int flags) |
87 { | 146 { |
| 147 RecordVfsEvent(VFS_IO_SYNC); |
| 148 |
88 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); | 149 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); |
89 return wrapped_file->pMethods->xSync(wrapped_file, flags); | 150 return wrapped_file->pMethods->xSync(wrapped_file, flags); |
90 } | 151 } |
91 | 152 |
92 int FileSize(sqlite3_file* sqlite_file, sqlite3_int64* size) | 153 int FileSize(sqlite3_file* sqlite_file, sqlite3_int64* size) |
93 { | 154 { |
| 155 RecordVfsEvent(VFS_IO_FILESIZE); |
| 156 |
94 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); | 157 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); |
95 return wrapped_file->pMethods->xFileSize(wrapped_file, size); | 158 return wrapped_file->pMethods->xFileSize(wrapped_file, size); |
96 } | 159 } |
97 | 160 |
98 int Lock(sqlite3_file* sqlite_file, int file_lock) | 161 int Lock(sqlite3_file* sqlite_file, int file_lock) |
99 { | 162 { |
100 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); | 163 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); |
101 return wrapped_file->pMethods->xLock(wrapped_file, file_lock); | 164 return wrapped_file->pMethods->xLock(wrapped_file, file_lock); |
102 } | 165 } |
103 | 166 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
147 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); | 210 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); |
148 wrapped_file->pMethods->xShmBarrier(wrapped_file); | 211 wrapped_file->pMethods->xShmBarrier(wrapped_file); |
149 } | 212 } |
150 | 213 |
151 int ShmUnmap(sqlite3_file *sqlite_file, int del) { | 214 int ShmUnmap(sqlite3_file *sqlite_file, int del) { |
152 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); | 215 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); |
153 return wrapped_file->pMethods->xShmUnmap(wrapped_file, del); | 216 return wrapped_file->pMethods->xShmUnmap(wrapped_file, del); |
154 } | 217 } |
155 | 218 |
156 int Fetch(sqlite3_file *sqlite_file, sqlite3_int64 off, int amt, void **pp) { | 219 int Fetch(sqlite3_file *sqlite_file, sqlite3_int64 off, int amt, void **pp) { |
| 220 RecordVfsEvent(VFS_IO_FETCH); |
| 221 UMA_HISTOGRAM_COUNTS("Sqlite.Vfs_Fetch", amt); |
| 222 |
157 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); | 223 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); |
158 return wrapped_file->pMethods->xFetch(wrapped_file, off, amt, pp); | 224 return wrapped_file->pMethods->xFetch(wrapped_file, off, amt, pp); |
159 } | 225 } |
160 | 226 |
161 int Unfetch(sqlite3_file *sqlite_file, sqlite3_int64 off, void *p) { | 227 int Unfetch(sqlite3_file *sqlite_file, sqlite3_int64 off, void *p) { |
162 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); | 228 sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file); |
163 return wrapped_file->pMethods->xUnfetch(wrapped_file, off, p); | 229 return wrapped_file->pMethods->xUnfetch(wrapped_file, off, p); |
164 } | 230 } |
165 | 231 |
166 #if defined(OS_MACOSX) && !defined(OS_IOS) | 232 #if defined(OS_MACOSX) && !defined(OS_IOS) |
167 // Helper to convert a POSIX path into a CoreFoundation path. | 233 // Helper to convert a POSIX path into a CoreFoundation path. |
168 base::ScopedCFTypeRef<CFURLRef> CFURLRefForPath(const char* path){ | 234 base::ScopedCFTypeRef<CFURLRef> CFURLRefForPath(const char* path){ |
169 base::ScopedCFTypeRef<CFStringRef> urlString( | 235 base::ScopedCFTypeRef<CFStringRef> urlString( |
170 CFStringCreateWithFileSystemRepresentation(kCFAllocatorDefault, path)); | 236 CFStringCreateWithFileSystemRepresentation(kCFAllocatorDefault, path)); |
171 base::ScopedCFTypeRef<CFURLRef> url( | 237 base::ScopedCFTypeRef<CFURLRef> url( |
172 CFURLCreateWithFileSystemPath(kCFAllocatorDefault, urlString, | 238 CFURLCreateWithFileSystemPath(kCFAllocatorDefault, urlString, |
173 kCFURLPOSIXPathStyle, FALSE)); | 239 kCFURLPOSIXPathStyle, FALSE)); |
174 return url; | 240 return url; |
175 } | 241 } |
176 #endif | 242 #endif |
177 | 243 |
178 int Open(sqlite3_vfs* vfs, const char* file_name, sqlite3_file* wrapper_file, | 244 int Open(sqlite3_vfs* vfs, const char* file_name, sqlite3_file* wrapper_file, |
179 int desired_flags, int* used_flags) { | 245 int desired_flags, int* used_flags) { |
| 246 RecordVfsEvent(VFS_OPEN); |
| 247 |
180 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs); | 248 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs); |
181 | 249 |
182 sqlite3_file* wrapped_file = static_cast<sqlite3_file*>( | 250 sqlite3_file* wrapped_file = static_cast<sqlite3_file*>( |
183 sqlite3_malloc(wrapped_vfs->szOsFile)); | 251 sqlite3_malloc(wrapped_vfs->szOsFile)); |
184 if (!wrapped_file) | 252 if (!wrapped_file) |
185 return SQLITE_NOMEM; | 253 return SQLITE_NOMEM; |
186 | 254 |
187 // NOTE(shess): SQLite's unixOpen() makes assumptions about the structure of | 255 // NOTE(shess): SQLite's unixOpen() makes assumptions about the structure of |
188 // |file_name|. Do not pass a local copy, here, only the passed-in value. | 256 // |file_name|. Do not pass a local copy, here, only the passed-in value. |
189 int rc = wrapped_vfs->xOpen(wrapped_vfs, | 257 int rc = wrapped_vfs->xOpen(wrapped_vfs, |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
291 // Methods above are valid for version 2. | 359 // Methods above are valid for version 2. |
292 Fetch, | 360 Fetch, |
293 Unfetch, | 361 Unfetch, |
294 }; | 362 }; |
295 file->methods = &io_methods; | 363 file->methods = &io_methods; |
296 } | 364 } |
297 return SQLITE_OK; | 365 return SQLITE_OK; |
298 } | 366 } |
299 | 367 |
300 int Delete(sqlite3_vfs* vfs, const char* file_name, int sync_dir) { | 368 int Delete(sqlite3_vfs* vfs, const char* file_name, int sync_dir) { |
| 369 RecordVfsEvent(VFS_DELETE); |
| 370 |
301 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs); | 371 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs); |
302 return wrapped_vfs->xDelete(wrapped_vfs, file_name, sync_dir); | 372 return wrapped_vfs->xDelete(wrapped_vfs, file_name, sync_dir); |
303 } | 373 } |
304 | 374 |
305 int Access(sqlite3_vfs* vfs, const char* file_name, int flag, int* res) { | 375 int Access(sqlite3_vfs* vfs, const char* file_name, int flag, int* res) { |
| 376 RecordVfsEvent(VFS_ACCESS); |
| 377 |
306 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs); | 378 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs); |
307 return wrapped_vfs->xAccess(wrapped_vfs, file_name, flag, res); | 379 return wrapped_vfs->xAccess(wrapped_vfs, file_name, flag, res); |
308 } | 380 } |
309 | 381 |
310 int FullPathname(sqlite3_vfs* vfs, const char* relative_path, | 382 int FullPathname(sqlite3_vfs* vfs, const char* relative_path, |
311 int buf_size, char* absolute_path) { | 383 int buf_size, char* absolute_path) { |
| 384 RecordVfsEvent(VFS_FULLPATHNAME); |
| 385 |
312 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs); | 386 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs); |
313 return wrapped_vfs->xFullPathname( | 387 return wrapped_vfs->xFullPathname( |
314 wrapped_vfs, relative_path, buf_size, absolute_path); | 388 wrapped_vfs, relative_path, buf_size, absolute_path); |
315 } | 389 } |
316 | 390 |
317 void* DlOpen(sqlite3_vfs* vfs, const char* filename) { | 391 void* DlOpen(sqlite3_vfs* vfs, const char* filename) { |
318 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs); | 392 sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs); |
319 return wrapped_vfs->xDlOpen(wrapped_vfs, filename); | 393 return wrapped_vfs->xDlOpen(wrapped_vfs, filename); |
320 } | 394 } |
321 | 395 |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
438 | 512 |
439 if (SQLITE_OK == sqlite3_vfs_register(wrapper_vfs.get(), 0)) { | 513 if (SQLITE_OK == sqlite3_vfs_register(wrapper_vfs.get(), 0)) { |
440 ANNOTATE_LEAKING_OBJECT_PTR(wrapper_vfs.get()); | 514 ANNOTATE_LEAKING_OBJECT_PTR(wrapper_vfs.get()); |
441 wrapper_vfs.release(); | 515 wrapper_vfs.release(); |
442 } | 516 } |
443 | 517 |
444 return sqlite3_vfs_find(kVFSName); | 518 return sqlite3_vfs_find(kVFSName); |
445 } | 519 } |
446 | 520 |
447 } // namespace sql | 521 } // namespace sql |
OLD | NEW |