Skip to content

Instantly share code, notes, and snippets.

@singerxt
Last active May 23, 2022 18:28
Show Gist options
  • Save singerxt/068c5a14756dd527c3e07239856fbcfd to your computer and use it in GitHub Desktop.
Save singerxt/068c5a14756dd527c3e07239856fbcfd to your computer and use it in GitHub Desktop.
// Maximum number of parts per upload
// DO NOT INCREASE IT. YOU WILL REACH GRPC MESSAGE SIZE LIMIT
const MAX_MULTI_UPLOAD_PARTS: u64 = 7000;
// 5 Tb.
const MAX_OBJECT_SIZE: u64 = 5 * 1024 * 1024 * 1024 * 1024;
// 5Gb
const MAX_PART_SIZE: u64 = 5 * 1024 * 1024 * 1024;
// 5Mb
const MIN_PART_SIZE: u64 = 5 * 1024 * 1024;
// 50Mb it's good for web client and handles maximal file size [MAX_OBJECT_SIZE]
const PREFERRED_PART_SIZE: u64 = 50 * 1024 * 1024;
type OptimalPartSize = u64;
fn calculate_optimal_part_size(file_size: u64) -> Result<OptimalPartSize, ()> {
if file_size > MAX_OBJECT_SIZE {
return Err(());
}
let optimal_size = match file_size {
// When upload is smaller or equal MinPartSize, we upload in just one part.
size if size <= PREFERRED_PART_SIZE => PREFERRED_PART_SIZE,
// Does the upload fit in MaxMultipartParts parts or less with MinPartSize.
size if size <= PREFERRED_PART_SIZE * MAX_MULTI_UPLOAD_PARTS => PREFERRED_PART_SIZE,
// Prerequisite: Be aware, that the result of an integer division (x/y) is
// ALWAYS rounded DOWN, as there are no digits behind the comma.
// In order to find out, whether we have an exact result or a rounded down
// one, we can check, whether the remainder of that division is 0 (x%y == 0).
//
// So if the result of (size/MaxMultipartParts) is not a rounded down value,
// then we can use it as our optimalPartSize. But if this division produces a
// remainder, we have to round up the result by adding +1. Otherwise our
// upload would not fit into MaxMultipartParts number of parts with that
// size. We would need an additional part in order to upload everything.
// While in almost all cases, we could skip the check for the remainder and
// just add +1 to every result, but there is one case, where doing that would
// doom our upload. When (MaxObjectSize == MaxPartSize * MaxMultipartParts),
// by adding +1, we would end up with an optimalPartSize > MaxPartSize.
// With the current S3 API specifications.
size if size % MAX_MULTI_UPLOAD_PARTS == 0 => size / MAX_MULTI_UPLOAD_PARTS,
// Having a remainder larger than 0 means, the float result would have
// digits after the comma (e.g. be something like 10.9). As a result, we can
// only squeeze our upload into MaxMultipartParts parts, if we rounded UP
// this division's result. That is what is happending here. We round up by
// adding +1, if the prior test for (remainder == 0) did not succeed.
size => size / MAX_MULTI_UPLOAD_PARTS + 1,
};
match optimal_size {
optimal_size if optimal_size > MAX_PART_SIZE => {
Err(())
}
_ => Ok(optimal_size)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment