@@ -91,6 +91,13 @@ typedef struct
91
91
char * manifest_checksum ;
92
92
} JsonManifestParseState ;
93
93
94
+ typedef struct JsonManifestParseIncrementalState
95
+ {
96
+ JsonLexContext lex ;
97
+ JsonSemAction sem ;
98
+ pg_cryptohash_ctx * manifest_ctx ;
99
+ } JsonManifestParseIncrementalState ;
100
+
94
101
static JsonParseErrorType json_manifest_object_start (void * state );
95
102
static JsonParseErrorType json_manifest_object_end (void * state );
96
103
static JsonParseErrorType json_manifest_array_start (void * state );
@@ -104,14 +111,99 @@ static void json_manifest_finalize_system_identifier(JsonManifestParseState *par
104
111
static void json_manifest_finalize_file (JsonManifestParseState * parse );
105
112
static void json_manifest_finalize_wal_range (JsonManifestParseState * parse );
106
113
static void verify_manifest_checksum (JsonManifestParseState * parse ,
107
- char * buffer , size_t size );
114
+ char * buffer , size_t size ,
115
+ pg_cryptohash_ctx * incr_ctx );
108
116
static void json_manifest_parse_failure (JsonManifestParseContext * context ,
109
117
char * msg );
110
118
111
119
static int hexdecode_char (char c );
112
120
static bool hexdecode_string (uint8 * result , char * input , int nbytes );
113
121
static bool parse_xlogrecptr (XLogRecPtr * result , char * input );
114
122
123
+ /*
124
+ * Set up for incremental parsing of the manifest.
125
+ *
126
+ */
127
+
128
+ JsonManifestParseIncrementalState *
129
+ json_parse_manifest_incremental_init (JsonManifestParseContext * context )
130
+ {
131
+ JsonManifestParseIncrementalState * incstate ;
132
+ JsonManifestParseState * parse ;
133
+ pg_cryptohash_ctx * manifest_ctx ;
134
+
135
+ incstate = palloc (sizeof (JsonManifestParseIncrementalState ));
136
+ parse = palloc (sizeof (JsonManifestParseState ));
137
+
138
+ parse -> context = context ;
139
+ parse -> state = JM_EXPECT_TOPLEVEL_START ;
140
+ parse -> saw_version_field = false;
141
+
142
+ makeJsonLexContextIncremental (& (incstate -> lex ), PG_UTF8 , true);
143
+
144
+ incstate -> sem .semstate = parse ;
145
+ incstate -> sem .object_start = json_manifest_object_start ;
146
+ incstate -> sem .object_end = json_manifest_object_end ;
147
+ incstate -> sem .array_start = json_manifest_array_start ;
148
+ incstate -> sem .array_end = json_manifest_array_end ;
149
+ incstate -> sem .object_field_start = json_manifest_object_field_start ;
150
+ incstate -> sem .object_field_end = NULL ;
151
+ incstate -> sem .array_element_start = NULL ;
152
+ incstate -> sem .array_element_end = NULL ;
153
+ incstate -> sem .scalar = json_manifest_scalar ;
154
+
155
+ manifest_ctx = pg_cryptohash_create (PG_SHA256 );
156
+ if (manifest_ctx == NULL )
157
+ context -> error_cb (context , "out of memory" );
158
+ if (pg_cryptohash_init (manifest_ctx ) < 0 )
159
+ context -> error_cb (context , "could not initialize checksum of manifest" );
160
+ incstate -> manifest_ctx = manifest_ctx ;
161
+
162
+ return incstate ;
163
+ }
164
+
165
+ /*
166
+ * parse the manifest in pieces.
167
+ *
168
+ * The caller must ensure that the final piece contains the final lines
169
+ * with the complete checksum.
170
+ */
171
+
172
+ void
173
+ json_parse_manifest_incremental_chunk (
174
+ JsonManifestParseIncrementalState * incstate , char * chunk , int size ,
175
+ bool is_last )
176
+ {
177
+ JsonParseErrorType res ,
178
+ expected ;
179
+ JsonManifestParseState * parse = incstate -> sem .semstate ;
180
+ JsonManifestParseContext * context = parse -> context ;
181
+
182
+ res = pg_parse_json_incremental (& (incstate -> lex ), & (incstate -> sem ),
183
+ chunk , size , is_last );
184
+
185
+ expected = is_last ? JSON_SUCCESS : JSON_INCOMPLETE ;
186
+
187
+ if (res != expected )
188
+ json_manifest_parse_failure (context ,
189
+ json_errdetail (res , & (incstate -> lex )));
190
+
191
+ if (is_last && parse -> state != JM_EXPECT_EOF )
192
+ json_manifest_parse_failure (context , "manifest ended unexpectedly" );
193
+
194
+ if (!is_last )
195
+ {
196
+ if (pg_cryptohash_update (incstate -> manifest_ctx ,
197
+ (uint8 * ) chunk , size ) < 0 )
198
+ context -> error_cb (context , "could not update checksum of manifest" );
199
+ }
200
+ else
201
+ {
202
+ verify_manifest_checksum (parse , chunk , size , incstate -> manifest_ctx );
203
+ }
204
+ }
205
+
206
+
115
207
/*
116
208
* Main entrypoint to parse a JSON-format backup manifest.
117
209
*
@@ -157,7 +249,7 @@ json_parse_manifest(JsonManifestParseContext *context, char *buffer,
157
249
json_manifest_parse_failure (context , "manifest ended unexpectedly" );
158
250
159
251
/* Verify the manifest checksum. */
160
- verify_manifest_checksum (& parse , buffer , size );
252
+ verify_manifest_checksum (& parse , buffer , size , NULL );
161
253
162
254
freeJsonLexContext (lex );
163
255
}
@@ -390,6 +482,8 @@ json_manifest_object_field_start(void *state, char *fname, bool isnull)
390
482
break ;
391
483
}
392
484
485
+ pfree (fname );
486
+
393
487
return JSON_SUCCESS ;
394
488
}
395
489
@@ -698,10 +792,14 @@ json_manifest_finalize_wal_range(JsonManifestParseState *parse)
698
792
* The last line of the manifest file is excluded from the manifest checksum,
699
793
* because the last line is expected to contain the checksum that covers
700
794
* the rest of the file.
795
+ *
796
+ * For an incremental parse, this will just be called on the last chunk of the
797
+ * manifest, and the cryptohash context paswed in. For a non-incremental
798
+ * parse incr_ctx will be NULL.
701
799
*/
702
800
static void
703
801
verify_manifest_checksum (JsonManifestParseState * parse , char * buffer ,
704
- size_t size )
802
+ size_t size , pg_cryptohash_ctx * incr_ctx )
705
803
{
706
804
JsonManifestParseContext * context = parse -> context ;
707
805
size_t i ;
@@ -736,11 +834,18 @@ verify_manifest_checksum(JsonManifestParseState *parse, char *buffer,
736
834
"last line not newline-terminated" );
737
835
738
836
/* Checksum the rest. */
739
- manifest_ctx = pg_cryptohash_create (PG_SHA256 );
740
- if (manifest_ctx == NULL )
741
- context -> error_cb (context , "out of memory" );
742
- if (pg_cryptohash_init (manifest_ctx ) < 0 )
743
- context -> error_cb (context , "could not initialize checksum of manifest" );
837
+ if (incr_ctx == NULL )
838
+ {
839
+ manifest_ctx = pg_cryptohash_create (PG_SHA256 );
840
+ if (manifest_ctx == NULL )
841
+ context -> error_cb (context , "out of memory" );
842
+ if (pg_cryptohash_init (manifest_ctx ) < 0 )
843
+ context -> error_cb (context , "could not initialize checksum of manifest" );
844
+ }
845
+ else
846
+ {
847
+ manifest_ctx = incr_ctx ;
848
+ }
744
849
if (pg_cryptohash_update (manifest_ctx , (uint8 * ) buffer , penultimate_newline + 1 ) < 0 )
745
850
context -> error_cb (context , "could not update checksum of manifest" );
746
851
if (pg_cryptohash_final (manifest_ctx , manifest_checksum_actual ,
0 commit comments