| 276 | // --------------------------------------------------------------------------- |
| 277 | |
| 278 | bool DiskChunkCache::initialize() { |
| 279 | std::string vfsName; |
| 280 | if (ctx_->custom_sqlite3_vfs_name.empty()) { |
| 281 | vfs_ = SQLite3VFS::create(true, false, false); |
| 282 | if (vfs_ == nullptr) { |
| 283 | return false; |
| 284 | } |
| 285 | vfsName = vfs_->name(); |
| 286 | } else { |
| 287 | vfsName = ctx_->custom_sqlite3_vfs_name; |
| 288 | } |
| 289 | sqlite3_open_v2(path_.c_str(), &hDB_, |
| 290 | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, |
| 291 | vfsName.c_str()); |
| 292 | if (!hDB_) { |
| 293 | pj_log(ctx_, PJ_LOG_ERROR, "Cannot open %s", path_.c_str()); |
| 294 | return false; |
| 295 | } |
| 296 | |
| 297 | // Cannot run more than 30 times / a bit more than one second. |
| 298 | for (int i = 0;; i++) { |
| 299 | int ret = |
| 300 | sqlite3_exec(hDB_, "BEGIN EXCLUSIVE", nullptr, nullptr, nullptr); |
| 301 | if (ret == SQLITE_OK) { |
| 302 | break; |
| 303 | } |
| 304 | if (ret != SQLITE_BUSY) { |
| 305 | pj_log(ctx_, PJ_LOG_ERROR, "%s", sqlite3_errmsg(hDB_)); |
| 306 | sqlite3_close(hDB_); |
| 307 | hDB_ = nullptr; |
| 308 | return false; |
| 309 | } |
| 310 | const char *max_iters = getenv("PROJ_LOCK_MAX_ITERS"); |
| 311 | if (i >= (max_iters && max_iters[0] ? atoi(max_iters) |
| 312 | : 30)) { // A bit more than 1 second |
| 313 | pj_log(ctx_, PJ_LOG_ERROR, "Cannot take exclusive lock on %s", |
| 314 | path_.c_str()); |
| 315 | sqlite3_close(hDB_); |
| 316 | hDB_ = nullptr; |
| 317 | return false; |
| 318 | } |
| 319 | pj_log(ctx_, PJ_LOG_TRACE, "Lock taken on cache. Waiting a bit..."); |
| 320 | // Retry every 5 ms for 50 ms, then every 10 ms for 100 ms, then |
| 321 | // every 100 ms |
| 322 | sleep_ms(i < 10 ? 5 : i < 20 ? 10 : 100); |
| 323 | } |
| 324 | char **pasResult = nullptr; |
| 325 | int nRows = 0; |
| 326 | int nCols = 0; |
| 327 | sqlite3_get_table(hDB_, |
| 328 | "SELECT 1 FROM sqlite_master WHERE name = 'properties'", |
| 329 | &pasResult, &nRows, &nCols, nullptr); |
| 330 | sqlite3_free_table(pasResult); |
| 331 | if (nRows == 0) { |
| 332 | if (!createDBStructure()) { |
| 333 | sqlite3_close(hDB_); |
| 334 | hDB_ = nullptr; |
| 335 | return false; |