Skip to content

Commit a9bc435

Browse files
committed
Add chunked uploading for initial bootstrapping for new clients to improve performance for #298
1 parent 3f34db5 commit a9bc435

File tree

2 files changed

+28
-10
lines changed

2 files changed

+28
-10
lines changed

backend/server/internal/server/api_handlers.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ func (s *Server) apiSubmitDumpHandler(w http.ResponseWriter, r *http.Request) {
142142
userId := getRequiredQueryParam(r, "user_id")
143143
srcDeviceId := getRequiredQueryParam(r, "source_device_id")
144144
requestingDeviceId := getRequiredQueryParam(r, "requesting_device_id")
145+
isChunk := getOptionalQueryParam(r, "is_chunk", s.isTestEnvironment) == "true"
145146
var entries []*shared.EncHistoryEntry
146147
err := json.NewDecoder(r.Body).Decode(&entries)
147148
if err != nil {
@@ -159,8 +160,10 @@ func (s *Server) apiSubmitDumpHandler(w http.ResponseWriter, r *http.Request) {
159160

160161
err = s.db.AddHistoryEntries(r.Context(), entries...)
161162
checkGormError(err)
162-
err = s.db.DumpRequestDeleteForUserAndDevice(r.Context(), userId, requestingDeviceId)
163-
checkGormError(err)
163+
if !isChunk {
164+
err = s.db.DumpRequestDeleteForUserAndDevice(r.Context(), userId, requestingDeviceId)
165+
checkGormError(err)
166+
}
164167

165168
version := getHishtoryVersion(r)
166169
remoteIPAddr := getRemoteAddr(r)

client/cmd/saveHistoryEntry.go

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -306,10 +306,21 @@ func deletePresavedEntries(ctx context.Context, entry *data.HistoryEntry, isRetr
306306
func handleDumpRequests(ctx context.Context, dumpRequests []*shared.DumpRequest) error {
307307
db := hctx.GetDb(ctx)
308308
config := hctx.GetConf(ctx)
309-
if len(dumpRequests) > 0 {
310-
lib.CheckFatalError(lib.RetrieveAdditionalEntriesFromRemote(ctx, "newclient"))
311-
entries, err := lib.Search(ctx, db, "", 0)
309+
if len(dumpRequests) == 0 {
310+
return nil
311+
}
312+
if config.IsOffline {
313+
return nil
314+
}
315+
lib.CheckFatalError(lib.RetrieveAdditionalEntriesFromRemote(ctx, "newclient"))
316+
chunkSize := 1000
317+
offset := 0
318+
for {
319+
entries, err := lib.SearchWithOffset(ctx, db, "", chunkSize, offset)
312320
lib.CheckFatalError(err)
321+
if len(entries) == 0 {
322+
break
323+
}
313324
var encEntries []*shared.EncHistoryEntry
314325
for _, entry := range entries {
315326
enc, err := data.EncryptHistoryEntry(config.UserSecret, *entry)
@@ -319,13 +330,17 @@ func handleDumpRequests(ctx context.Context, dumpRequests []*shared.DumpRequest)
319330
reqBody, err := json.Marshal(encEntries)
320331
lib.CheckFatalError(err)
321332
for _, dumpRequest := range dumpRequests {
322-
if !config.IsOffline {
323-
// TODO: Test whether this fails if the data is extremely large? It may need to be chunked
324-
_, err := lib.ApiPost(ctx, "/api/v1/submit-dump?user_id="+dumpRequest.UserId+"&requesting_device_id="+dumpRequest.RequestingDeviceId+"&source_device_id="+config.DeviceId, "application/json", reqBody)
325-
lib.CheckFatalError(err)
326-
}
333+
_, err := lib.ApiPost(ctx, "/api/v1/submit-dump?user_id="+dumpRequest.UserId+"&requesting_device_id="+dumpRequest.RequestingDeviceId+"&source_device_id="+config.DeviceId+"&is_chunk=true", "application/json", reqBody)
334+
lib.CheckFatalError(err)
327335
}
328336
}
337+
// Send a final dump response without the `is_chunk` param so that the backend knows we're done
338+
reqBody, err := json.Marshal([]*shared.EncHistoryEntry{})
339+
lib.CheckFatalError(err)
340+
for _, dumpRequest := range dumpRequests {
341+
_, err := lib.ApiPost(ctx, "/api/v1/submit-dump?user_id="+dumpRequest.UserId+"&requesting_device_id="+dumpRequest.RequestingDeviceId+"&source_device_id="+config.DeviceId+"&is_chunk=true", "application/json", reqBody)
342+
lib.CheckFatalError(err)
343+
}
329344
return nil
330345
}
331346

0 commit comments

Comments
 (0)