File: sql_store_base.cc

package info (click to toggle)
chromium 138.0.7204.183-1~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-proposed-updates
  • size: 6,080,960 kB
  • sloc: cpp: 34,937,079; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,954; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,811; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (196 lines) | stat: -rw-r--r-- 6,385 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/offline_pages/task/sql_store_base.h"

#include <iterator>
#include <utility>

#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "base/trace_event/trace_event.h"

namespace offline_pages {
namespace {

bool PrepareDirectory(const base::FilePath& path) {
  base::File::Error error = base::File::FILE_OK;
  if (!base::DirectoryExists(path.DirName())) {
    if (!base::CreateDirectoryAndGetError(path.DirName(), &error)) {
      DLOG(ERROR) << "Failed to create prefetch db directory: "
                  << base::File::ErrorToString(error);
      return false;
    }
  }
  return true;
}

// TODO(fgorski): This function and this part of the system in general could
// benefit from a better status code reportable through UMA to better capture
// the reason for failure, aiding the process of repeated attempts to
// open/initialize the database.
bool InitializeSync(
    sql::Database* db,
    const base::FilePath& path,
    base::OnceCallback<bool(sql::Database*)> initialize_schema) {
  const bool in_memory = path.empty();
  if (!in_memory && !PrepareDirectory(path))
    return false;

  bool open_db_result = false;
  if (in_memory)
    open_db_result = db->OpenInMemory();
  else
    open_db_result = db->Open(path);

  if (!open_db_result) {
    DLOG(ERROR) << "Failed to open database, in memory: " << in_memory;
    return false;
  }

  return std::move(initialize_schema).Run(db);
}

void CloseDatabaseSync(
    sql::Database* db,
    scoped_refptr<base::SingleThreadTaskRunner> callback_runner,
    base::OnceClosure callback) {
  if (db)
    db->Close();
  callback_runner->PostTask(FROM_HERE, std::move(callback));
}

}  // namespace

// static
constexpr base::TimeDelta SqlStoreBase::kClosingDelay;

SqlStoreBase::SqlStoreBase(
    sql::Database::Tag histogram_tag,
    scoped_refptr<base::SequencedTaskRunner> background_task_runner,
    const base::FilePath& file_path)
    : background_task_runner_(background_task_runner),
      histogram_tag_(histogram_tag),
      db_file_path_(file_path),
      db_(nullptr, base::OnTaskRunnerDeleter(background_task_runner_)) {}

SqlStoreBase::~SqlStoreBase() = default;

void SqlStoreBase::SetInitializationStatusForTesting(
    InitializationStatus initialization_status,
    bool reset_db) {
  initialization_status_ = initialization_status;
  if (reset_db)
    db_.reset(nullptr);
}

void SqlStoreBase::Initialize(base::OnceClosure pending_command) {
  OnOpenStart(last_closing_time_);

  DCHECK_EQ(initialization_status_, InitializationStatus::kNotInitialized);
  initialization_status_ = InitializationStatus::kInProgress;

  // This is how we reset a pointer and provide deleter. This is necessary to
  // ensure that we can close the store more than once.
  db_ = DatabaseUniquePtr(
      new sql::Database(sql::DatabaseOptions().set_preload(true),
                        histogram_tag_),
      base::OnTaskRunnerDeleter(background_task_runner_));

  background_task_runner_->PostTaskAndReplyWithResult(
      FROM_HERE,
      base::BindOnce(&InitializeSync, db_.get(), db_file_path_,
                     GetSchemaInitializationFunction()),
      base::BindOnce(&SqlStoreBase::InitializeDone,
                     weak_ptr_factory_.GetWeakPtr(),
                     std::move(pending_command)));
}

void SqlStoreBase::InitializeDone(base::OnceClosure pending_command,
                                  bool success) {
  DCHECK_EQ(initialization_status_, InitializationStatus::kInProgress);
  if (success) {
    initialization_status_ = InitializationStatus::kSuccess;
  } else {
    initialization_status_ = InitializationStatus::kFailure;
    db_.reset();
  }

  CHECK(!pending_command.is_null());
  std::move(pending_command).Run();
  for (auto command_iter = std::make_move_iterator(pending_commands_.begin());
       command_iter != std::make_move_iterator(pending_commands_.end());
       ++command_iter) {
    (*command_iter).Run();
  }
  pending_commands_.clear();

  // Once pending commands are empty, we get back to kNotInitialized state, to
  // make it possible to retry initialization next time a DB operation is
  // attempted.
  if (initialization_status_ == InitializationStatus::kFailure)
    initialization_status_ = InitializationStatus::kNotInitialized;

  OnOpenDone(success);
}

void SqlStoreBase::ExecuteInternal(base::OnceClosure command) {
  if (initialization_status_ == InitializationStatus::kInProgress) {
    pending_commands_.push_back(std::move(command));
    return;
  }

  if (initialization_status_ == InitializationStatus::kNotInitialized) {
    Initialize(std::move(command));
    return;
  }

  std::move(command).Run();
}

sql::Database* SqlStoreBase::ExecuteBegin() {
  OnTaskBegin(initialization_status_ == InitializationStatus::kSuccess);
  // Ensure that any scheduled close operations are canceled.
  closing_weak_ptr_factory_.InvalidateWeakPtrs();

  return initialization_status_ == InitializationStatus::kSuccess ? db_.get()
                                                                  : nullptr;
}

void SqlStoreBase::CloseInternal() {
  OnCloseStart(initialization_status_);

  last_closing_time_ = base::TimeTicks::Now();

  initialization_status_ = InitializationStatus::kNotInitialized;
  background_task_runner_->PostTask(
      FROM_HERE,
      base::BindOnce(
          &CloseDatabaseSync, db_.get(),
          base::SingleThreadTaskRunner::GetCurrentDefault(),
          base::BindOnce(&SqlStoreBase::CloseInternalDone,
                         weak_ptr_factory_.GetWeakPtr(), std::move(db_))));
}

void SqlStoreBase::RescheduleClosingBefore() {
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
      FROM_HERE,
      base::BindOnce(&SqlStoreBase::CloseInternal,
                     closing_weak_ptr_factory_.GetWeakPtr()),
      kClosingDelay);

  // Note: the time recorded for this trace step will include thread hop wait
  // times to the background thread and back.
  OnTaskRunComplete();
}

void SqlStoreBase::CloseInternalDone(DatabaseUniquePtr db) {
  db.reset();
  OnCloseComplete();
}

}  // namespace offline_pages