Skip to content

Commit ecceba4

Browse files
committed
Reduced memory use on processing the new upload.
1 parent 5ef6f75 commit ecceba4

File tree

2 files changed

+27
-11
lines changed

2 files changed

+27
-11
lines changed

app/lib/package/backend.dart

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -904,8 +904,7 @@ class PackageBackend {
904904
_logger.info('Examining tarball content ($guid).');
905905
final sw = Stopwatch()..start();
906906
final file = File(filename);
907-
final fileBytes = await file.readAsBytes();
908-
final sha256Hash = sha256.convert(fileBytes).bytes;
907+
final sha256Hash = (await file.openRead().transform(sha256).single).bytes;
909908
final archive = await summarizePackageArchive(
910909
filename,
911910
maxContentLength: maxAssetContentLength,
@@ -946,7 +945,7 @@ class PackageBackend {
946945
await tarballStorage.matchArchiveContentInCanonical(
947946
pubspec.name,
948947
versionString,
949-
fileBytes,
948+
file,
950949
);
951950
if (canonicalContentMatch == ContentMatchStatus.different) {
952951
throw PackageRejectedException.versionExists(

app/lib/package/tarball_storage.dart

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5-
import 'dart:typed_data';
5+
import 'dart:io';
66

77
import 'package:crypto/crypto.dart';
88
import 'package:gcloud/storage.dart';
@@ -69,26 +69,43 @@ class TarballStorage {
6969
Future<ContentMatchStatus> matchArchiveContentInCanonical(
7070
String package,
7171
String version,
72-
Uint8List bytes,
72+
File file,
7373
) async {
7474
final objectName = tarballObjectName(package, version);
7575
final info = await _canonicalBucket.tryInfo(objectName);
7676
if (info == null) {
7777
return ContentMatchStatus.missing;
7878
}
79-
if (info.length != bytes.length) {
79+
if (info.length != await file.length()) {
8080
return ContentMatchStatus.different;
8181
}
82-
final md5hash = md5.convert(bytes).bytes;
82+
final md5hash = (await file.openRead().transform(md5).single).bytes;
8383
if (!md5hash.byteToByteEquals(info.md5Hash)) {
8484
return ContentMatchStatus.different;
8585
}
86-
final objectBytes = await _canonicalBucket.readAsBytes(objectName);
87-
if (bytes.byteToByteEquals(objectBytes)) {
88-
return ContentMatchStatus.same;
89-
} else {
86+
// limit memory use while doing the byte-to-byte comparison
87+
final raf = await file.open();
88+
var remainingLength = info.length;
89+
try {
90+
await for (final chunk in _canonicalBucket.read(objectName)) {
91+
if (chunk.isEmpty) continue;
92+
remainingLength -= chunk.length;
93+
if (remainingLength < 0) {
94+
return ContentMatchStatus.different;
95+
}
96+
// TODO: consider rewriting to fixed-length chunk comparison
97+
final fileChunk = await raf.read(chunk.length);
98+
if (!fileChunk.byteToByteEquals(chunk)) {
99+
return ContentMatchStatus.different;
100+
}
101+
}
102+
} finally {
103+
await raf.close();
104+
}
105+
if (remainingLength != 0) {
90106
return ContentMatchStatus.different;
91107
}
108+
return ContentMatchStatus.same;
92109
}
93110

94111
/// Copies the uploaded object from the temp bucket to the canonical bucket.

0 commit comments

Comments
 (0)