@@ -4,26 +4,27 @@ use alloc::vec::Vec;
4
4
use serde:: { Deserialize , Deserializer , Serialize } ;
5
5
use serde_json as json;
6
6
7
+ use crate :: error:: { PSResult , SQLiteError } ;
7
8
use sqlite_nostd as sqlite;
8
9
use sqlite_nostd:: { Connection , ResultCode } ;
9
- use crate :: error:: { SQLiteError , PSResult } ;
10
10
11
11
use crate :: ext:: SafeManagedStmt ;
12
12
use crate :: sync_types:: { BucketChecksum , Checkpoint , StreamingSyncLine } ;
13
13
use crate :: util:: * ;
14
14
15
15
// Run inside a transaction
16
- pub fn insert_operation (
17
- db : * mut sqlite:: sqlite3 , data : & str ) -> Result < ( ) , SQLiteError > {
16
+ pub fn insert_operation ( db : * mut sqlite:: sqlite3 , data : & str ) -> Result < ( ) , SQLiteError > {
18
17
// language=SQLite
19
- let statement = db. prepare_v2 ( "\
18
+ let statement = db. prepare_v2 (
19
+ "\
20
20
SELECT
21
21
json_extract(e.value, '$.bucket') as bucket,
22
22
json_extract(e.value, '$.data') as data,
23
23
json_extract(e.value, '$.has_more') as has_more,
24
24
json_extract(e.value, '$.after') as after,
25
25
json_extract(e.value, '$.next_after') as next_after
26
- FROM json_each(json_extract(?, '$.buckets')) e" ) ?;
26
+ FROM json_each(json_extract(?, '$.buckets')) e" ,
27
+ ) ?;
27
28
statement. bind_text ( 1 , data, sqlite:: Destructor :: STATIC ) ?;
28
29
29
30
while statement. step ( ) ? == ResultCode :: ROW {
@@ -39,9 +40,14 @@ FROM json_each(json_extract(?, '$.buckets')) e")?;
39
40
Ok ( ( ) )
40
41
}
41
42
42
- pub fn insert_bucket_operations ( db : * mut sqlite:: sqlite3 , bucket : & str , data : & str ) -> Result < ( ) , SQLiteError > {
43
+ pub fn insert_bucket_operations (
44
+ db : * mut sqlite:: sqlite3 ,
45
+ bucket : & str ,
46
+ data : & str ,
47
+ ) -> Result < ( ) , SQLiteError > {
43
48
// language=SQLite
44
- let iterate_statement = db. prepare_v2 ( "\
49
+ let iterate_statement = db. prepare_v2 (
50
+ "\
45
51
SELECT
46
52
json_extract(e.value, '$.op_id') as op_id,
47
53
json_extract(e.value, '$.op') as op,
@@ -50,32 +56,35 @@ SELECT
50
56
json_extract(e.value, '$.checksum') as checksum,
51
57
json_extract(e.value, '$.data') as data,
52
58
json_extract(e.value, '$.subkey') as subkey
53
- FROM json_each(?) e" ) ?;
59
+ FROM json_each(?) e" ,
60
+ ) ?;
54
61
iterate_statement. bind_text ( 1 , data, sqlite:: Destructor :: STATIC ) ?;
55
62
56
63
// language=SQLite
57
- let supersede_statement = db. prepare_v2 ( "\
64
+ let supersede_statement = db. prepare_v2 (
65
+ "\
58
66
UPDATE ps_oplog SET
59
67
superseded = 1,
60
68
op = 2,
61
69
data = NULL
62
70
WHERE ps_oplog.superseded = 0
63
71
AND unlikely(ps_oplog.bucket = ?1)
64
- AND ps_oplog.key = ?2" ) ?;
72
+ AND ps_oplog.key = ?2" ,
73
+ ) ?;
65
74
supersede_statement. bind_text ( 1 , bucket, sqlite:: Destructor :: STATIC ) ?;
66
75
67
76
// language=SQLite
68
77
let insert_statement = db. prepare_v2 ( "\
69
- INSERT INTO ps_oplog(bucket, op_id, op, key, row_type, row_id, data, hash, superseded) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ? )") ?;
78
+ INSERT INTO ps_oplog(bucket, op_id, op, key, row_type, row_id, data, hash, superseded) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 0 )") ?;
70
79
insert_statement. bind_text ( 1 , bucket, sqlite:: Destructor :: STATIC ) ?;
71
80
72
81
// language=SQLite
73
82
let bucket_statement = db. prepare_v2 ( "INSERT OR IGNORE INTO ps_buckets(name) VALUES(?)" ) ?;
74
83
bucket_statement. bind_text ( 1 , bucket, sqlite:: Destructor :: STATIC ) ?;
75
84
bucket_statement. exec ( ) ?;
76
85
77
- let mut first_op: Option < i64 > = None ;
78
86
let mut last_op: Option < i64 > = None ;
87
+ let mut add_checksum: i32 = 0 ;
79
88
80
89
while iterate_statement. step ( ) ? == ResultCode :: ROW {
81
90
let op_id = iterate_statement. column_int64 ( 0 ) ?;
@@ -86,11 +95,8 @@ INSERT INTO ps_oplog(bucket, op_id, op, key, row_type, row_id, data, hash, super
86
95
let op_data = iterate_statement. column_text ( 5 ) ;
87
96
88
97
last_op = Some ( op_id) ;
89
- if first_op. is_none ( ) {
90
- first_op = Some ( op_id) ;
91
- }
92
98
93
- if op == "PUT" || op == "REMOVE" || op == "MOVE" {
99
+ if op == "PUT" || op == "REMOVE" {
94
100
let key: String ;
95
101
if let ( Ok ( object_type) , Ok ( object_id) ) = ( object_type. as_ref ( ) , object_id. as_ref ( ) ) {
96
102
let subkey = iterate_statement. column_text ( 6 ) . unwrap_or ( "null" ) ;
@@ -101,8 +107,7 @@ INSERT INTO ps_oplog(bucket, op_id, op, key, row_type, row_id, data, hash, super
101
107
key = String :: from ( "" ) ;
102
108
}
103
109
104
- let superseded = if op == "MOVE" { 1 } else { 0 } ;
105
- let opi = if op == "MOVE" { 2 } else if op == "PUT" { 3 } else { 4 } ;
110
+ let opi = if op == "PUT" { 3 } else { 4 } ;
106
111
insert_statement. bind_int64 ( 2 , op_id) ?;
107
112
insert_statement. bind_int ( 3 , opi) ?;
108
113
if key == "" {
@@ -125,8 +130,9 @@ INSERT INTO ps_oplog(bucket, op_id, op, key, row_type, row_id, data, hash, super
125
130
}
126
131
127
132
insert_statement. bind_int ( 8 , checksum) ?;
128
- insert_statement. bind_int ( 9 , superseded) ?;
129
133
insert_statement. exec ( ) ?;
134
+ } else if op == "MOVE" {
135
+ add_checksum = add_checksum. wrapping_add ( checksum) ;
130
136
} else if op == "CLEAR" {
131
137
// Any remaining PUT operations should get an implicit REMOVE
132
138
// language=SQLite
@@ -137,77 +143,59 @@ INSERT INTO ps_oplog(bucket, op_id, op, key, row_type, row_id, data, hash, super
137
143
// And we need to re-apply all of those.
138
144
// We also replace the checksum with the checksum of the CLEAR op.
139
145
// language=SQLite
140
- let clear_statement2 = db. prepare_v2 ( "UPDATE ps_buckets SET last_applied_op = 0, add_checksum = ?1 WHERE name = ?2" ) ?;
146
+ let clear_statement2 = db. prepare_v2 (
147
+ "UPDATE ps_buckets SET last_applied_op = 0, add_checksum = ?1 WHERE name = ?2" ,
148
+ ) ?;
141
149
clear_statement2. bind_text ( 2 , bucket, sqlite:: Destructor :: STATIC ) ?;
142
150
clear_statement2. bind_int ( 1 , checksum) ?;
143
151
clear_statement2. exec ( ) ?;
152
+
153
+ add_checksum = 0 ;
144
154
}
145
155
}
146
156
147
157
if let Some ( last_op) = & last_op {
148
158
// language=SQLite
149
- let statement = db. prepare_v2 ( "UPDATE ps_buckets SET last_op = ?1 WHERE name = ?2" ) ?;
150
- statement. bind_text ( 2 , bucket, sqlite:: Destructor :: STATIC ) ?;
151
- statement. bind_int64 ( 1 , * last_op) ?;
152
- statement. exec ( ) ?;
153
- }
154
-
155
-
156
- // Compact superseded ops immediately
157
- if let ( Some ( first_op) , Some ( last_op) ) = ( & first_op, & last_op) {
158
- // language=SQLite
159
- let statement = db. prepare_v2 ( "UPDATE ps_buckets
160
- SET add_checksum = add_checksum + (SELECT IFNULL(SUM(hash), 0)
161
- FROM ps_oplog AS oplog
162
- WHERE superseded = 1
163
- AND oplog.bucket = ?1
164
- AND oplog.op_id >= ?2
165
- AND oplog.op_id <= ?3)
166
- WHERE ps_buckets.name = ?1" ) ?;
159
+ let statement = db. prepare_v2 (
160
+ "UPDATE ps_buckets
161
+ SET last_op = ?2,
162
+ add_checksum = add_checksum + ?3
163
+ WHERE name = ?1" ,
164
+ ) ?;
167
165
statement. bind_text ( 1 , bucket, sqlite:: Destructor :: STATIC ) ?;
168
- statement. bind_int64 ( 2 , * first_op) ?;
169
- statement. bind_int64 ( 3 , * last_op) ?;
170
- statement. exec ( ) ?;
166
+ statement. bind_int64 ( 2 , * last_op) ?;
167
+ statement. bind_int ( 3 , add_checksum) ?;
171
168
172
- // language=SQLite
173
- let statement = db. prepare_v2 ( "DELETE
174
- FROM ps_oplog
175
- WHERE superseded = 1
176
- AND bucket = ?
177
- AND op_id >= ?
178
- AND op_id <= ?" ) ?;
179
- statement. bind_text ( 1 , bucket, sqlite:: Destructor :: STATIC ) ?;
180
- statement. bind_int64 ( 2 , * first_op) ?;
181
- statement. bind_int64 ( 3 , * last_op) ?;
182
169
statement. exec ( ) ?;
183
170
}
184
171
185
172
Ok ( ( ) )
186
173
}
187
174
188
- pub fn clear_remove_ops (
189
- db : * mut sqlite:: sqlite3 , _data : & str ) -> Result < ( ) , SQLiteError > {
190
-
175
+ pub fn clear_remove_ops ( db : * mut sqlite:: sqlite3 , _data : & str ) -> Result < ( ) , SQLiteError > {
191
176
// language=SQLite
192
- let statement = db . prepare_v2 (
193
- "SELECT name, last_applied_op FROM ps_buckets WHERE pending_delete = 0" ) ?;
177
+ let statement =
178
+ db . prepare_v2 ( "SELECT name, last_applied_op FROM ps_buckets WHERE pending_delete = 0" ) ?;
194
179
195
180
// language=SQLite
196
- let update_statement = db. prepare_v2 ( "UPDATE ps_buckets
181
+ let update_statement = db. prepare_v2 (
182
+ "UPDATE ps_buckets
197
183
SET add_checksum = add_checksum + (SELECT IFNULL(SUM(hash), 0)
198
184
FROM ps_oplog AS oplog
199
185
WHERE (superseded = 1 OR op != 3)
200
186
AND oplog.bucket = ?1
201
187
AND oplog.op_id <= ?2)
202
- WHERE ps_buckets.name = ?1" ) ?;
188
+ WHERE ps_buckets.name = ?1" ,
189
+ ) ?;
203
190
204
191
// language=SQLite
205
- let delete_statement = db. prepare_v2 ( "DELETE
192
+ let delete_statement = db. prepare_v2 (
193
+ "DELETE
206
194
FROM ps_oplog
207
195
WHERE (superseded = 1 OR op != 3)
208
196
AND bucket = ?1
209
- AND op_id <= ?2" ) ? ;
210
-
197
+ AND op_id <= ?2" ,
198
+ ) ? ;
211
199
212
200
while statement. step ( ) ? == ResultCode :: ROW {
213
201
// Note: Each iteration here may be run in a separate transaction.
@@ -228,10 +216,7 @@ pub fn clear_remove_ops(
228
216
Ok ( ( ) )
229
217
}
230
218
231
-
232
- pub fn delete_pending_buckets (
233
- db : * mut sqlite:: sqlite3 , _data : & str ) -> Result < ( ) , SQLiteError > {
234
-
219
+ pub fn delete_pending_buckets ( db : * mut sqlite:: sqlite3 , _data : & str ) -> Result < ( ) , SQLiteError > {
235
220
// language=SQLite
236
221
let statement = db. prepare_v2 (
237
222
"DELETE FROM ps_oplog WHERE bucket IN (SELECT name FROM ps_buckets WHERE pending_delete = 1 AND last_applied_op = last_op AND last_op >= target_op)" ) ?;
@@ -244,31 +229,27 @@ pub fn delete_pending_buckets(
244
229
Ok ( ( ) )
245
230
}
246
231
247
-
248
- pub fn delete_bucket (
249
- db : * mut sqlite:: sqlite3 , name : & str ) -> Result < ( ) , SQLiteError > {
250
-
232
+ pub fn delete_bucket ( db : * mut sqlite:: sqlite3 , name : & str ) -> Result < ( ) , SQLiteError > {
251
233
let id = gen_uuid ( ) ;
252
234
let new_name = format ! ( "$delete_{}_{}" , name, id. hyphenated( ) . to_string( ) ) ;
253
235
254
236
// language=SQLite
255
237
let statement = db. prepare_v2 (
256
- "UPDATE ps_oplog SET op=4, data=NULL, bucket=?1 WHERE op=3 AND superseded=0 AND bucket=?2" ) ?;
238
+ "UPDATE ps_oplog SET op=4, data=NULL, bucket=?1 WHERE op=3 AND superseded=0 AND bucket=?2" ,
239
+ ) ?;
257
240
statement. bind_text ( 1 , & new_name, sqlite:: Destructor :: STATIC ) ?;
258
241
statement. bind_text ( 2 , & name, sqlite:: Destructor :: STATIC ) ?;
259
242
statement. exec ( ) ?;
260
243
261
244
// Rename bucket
262
245
// language=SQLite
263
- let statement = db. prepare_v2 (
264
- "UPDATE ps_oplog SET bucket=?1 WHERE bucket=?2" ) ?;
246
+ let statement = db. prepare_v2 ( "UPDATE ps_oplog SET bucket=?1 WHERE bucket=?2" ) ?;
265
247
statement. bind_text ( 1 , & new_name, sqlite:: Destructor :: STATIC ) ?;
266
248
statement. bind_text ( 2 , name, sqlite:: Destructor :: STATIC ) ?;
267
249
statement. exec ( ) ?;
268
250
269
251
// language=SQLite
270
- let statement = db. prepare_v2 (
271
- "DELETE FROM ps_buckets WHERE name = ?1" ) ?;
252
+ let statement = db. prepare_v2 ( "DELETE FROM ps_buckets WHERE name = ?1" ) ?;
272
253
statement. bind_text ( 1 , name, sqlite:: Destructor :: STATIC ) ?;
273
254
statement. exec ( ) ?;
274
255
@@ -281,13 +262,8 @@ pub fn delete_bucket(
281
262
Ok ( ( ) )
282
263
}
283
264
284
-
285
- pub fn stream_operation (
286
- db : * mut sqlite:: sqlite3 , data : & str ) -> Result < ( ) , SQLiteError > {
287
-
265
+ pub fn stream_operation ( db : * mut sqlite:: sqlite3 , data : & str ) -> Result < ( ) , SQLiteError > {
288
266
let line: StreamingSyncLine = serde_json:: from_str ( data) ?;
289
267
290
268
Ok ( ( ) )
291
269
}
292
-
293
-
0 commit comments