Branch data Line data Source code
1 : : #include "precizer.h"
2 : :
3 : : /**
4 : : * @brief Start a batch before the main traversal saves a file record
5 : : *
6 : : * The batch uses the primary connection settings established by db_init().
7 : : * Later saves join the active batch without moving its deadline. Dry-run
8 : : * does not start transactions. Outside dry-run, the caller supplies a writable
9 : : * connection
10 : : *
11 : : * @return SUCCESS when a batch is ready or unnecessary, otherwise FAILURE
12 : : */
13 : 3610 : Return db_file_transaction_begin(void)
14 : : {
15 : : /* Status returned by this function through provide()
16 : : Default value assumes successful completion */
17 : 3610 : Return status = SUCCESS;
18 : :
19 [ + + ]: 3610 : if(config->dry_run == true)
20 : : {
21 : 694 : provide(status);
22 : : }
23 : :
24 : : /*
25 : : * Reuse the current batch without starting another transaction or resetting
26 : : * its timer. Autocommit must remain disabled while the batch is active.
27 : : * If SQLite has ended the transaction (for example, after an automatic
28 : : * rollback), report failure to prevent further writes outside the batch
29 : : */
30 [ + + ]: 2916 : if(config->file_transaction_active == true)
31 : : {
32 [ - + ]: 2597 : if(sqlite3_get_autocommit(config->db) != 0)
33 : : {
34 : 0 : slog(ERROR,"File traversal transaction ended before commit\n");
35 : 0 : status = FAILURE;
36 : : }
37 : :
38 : 2597 : provide(status);
39 : : }
40 : :
41 : : /* Use the primary connection settings established by db_init() */
42 : 319 : const int rc = sqlite3_exec(config->db,"BEGIN IMMEDIATE;",NULL,NULL,NULL);
43 : :
44 [ - + ]: 319 : if(rc != SQLITE_OK)
45 : : {
46 : 0 : log_sqlite_error(config->db,rc,NULL,"Failed to begin file traversal transaction");
47 : 0 : status = FAILURE;
48 : : } else {
49 : 319 : config->file_transaction_active = true;
50 : 319 : config->file_transaction_started_ns = cur_time_monotonic_ns();
51 : : }
52 : :
53 : 319 : provide(status);
54 : : }
55 : :
56 : : /**
57 : : * @brief Commit the current batch of file records, if one is active
58 : : * @return SUCCESS after commit or when no batch is active, otherwise FAILURE
59 : : */
60 : 620 : Return db_file_transaction_commit(void)
61 : : {
62 : : /* Status returned by this function through provide()
63 : : Default value assumes successful completion */
64 : 620 : Return status = SUCCESS;
65 : :
66 [ + + ]: 620 : if(config->file_transaction_active == true)
67 : : {
68 : 317 : const int rc = sqlite3_exec(config->db,"COMMIT;",NULL,NULL,NULL);
69 : :
70 [ + + ]: 317 : if(rc != SQLITE_OK)
71 : : {
72 : 1 : log_sqlite_error(config->db,rc,NULL,"Failed to commit file traversal transaction");
73 : 1 : status = FAILURE;
74 : : } else {
75 : 316 : config->file_transaction_active = false;
76 : : }
77 : : }
78 : :
79 : 620 : provide(status);
80 : : }
81 : :
82 : : /**
83 : : * @brief Commit pending file records when their shared interval has elapsed
84 : : * @param now_ns Current monotonic time in nanoseconds
85 : : * @return SUCCESS when the deadline was handled, otherwise FAILURE
86 : : */
87 : 24525 : Return db_file_transaction_check(const long long int now_ns)
88 : : {
89 : : /* Status returned by this function through provide()
90 : : Default value assumes successful completion */
91 : 24525 : Return status = SUCCESS;
92 : :
93 [ + + ]: 24525 : if(config->file_transaction_active == true
94 [ + + ]: 24523 : && now_ns - config->file_transaction_started_ns >= DB_CHECKPOINT_INTERVAL_NS)
95 : : {
96 : 1 : call(db_file_transaction_commit());
97 : : }
98 : :
99 : 24525 : provide(status);
100 : : }
101 : :
102 : : /**
103 : : * @brief Roll back any pending main-traversal transaction
104 : : *
105 : : * Does nothing when no file transaction is active. If SQLite already rolled
106 : : * back automatically, only the traversal transaction flag is cleared
107 : : *
108 : : * Database operations after traversal use the same connection settings
109 : : *
110 : : * @return Cleanup status, to be combined with the traversal result by the caller
111 : : */
112 : 615 : Return db_file_transaction_rollback(void)
113 : : {
114 : : /* Status returned by this function through provide()
115 : : Default value assumes successful completion */
116 : 615 : Return status = SUCCESS;
117 : :
118 [ + + ]: 615 : if(config->file_transaction_active == true)
119 : : {
120 : : /* SQLite may have rolled back automatically after an I/O or storage error */
121 [ + - ]: 3 : if(sqlite3_get_autocommit(config->db) == 0)
122 : : {
123 : 3 : const int rc = sqlite3_exec(config->db,"ROLLBACK;",NULL,NULL,NULL);
124 : :
125 [ - + ]: 3 : if(rc != SQLITE_OK)
126 : : {
127 : 0 : log_sqlite_error(config->db,rc,NULL,"Failed to roll back file traversal transaction");
128 : 0 : status = FAILURE;
129 : : }
130 : : }
131 : :
132 : : /* Clear the flag after a successful rollback or if SQLite had already
133 : : ended the transaction. Leave it set on failure because the transaction's
134 : : state is uncertain */
135 [ + - ]: 3 : if(SUCCESS & status)
136 : : {
137 : 3 : config->file_transaction_active = false;
138 : : }
139 : : }
140 : :
141 : 615 : provide(status);
142 : : }
|