Hi!

On Fri, 2022-11-11 at 19:15:59 +0100, Manuel A. Fernandez Montecelo wrote:
> Package: dpkg
> Version: 1.21.9
> Severity: normal
> X-Debbugs-Cc: m...@debian.org, debian-wb-t...@lists.debian.org

> After some investigation by aurel32 and myself, this was traced back to the
> commit f8d254943051e085040367d689048c00f31514c3 [2], in which the calculation 
> of
> the memory that can be used, to determine the number of threads to use, was
> changed from half of the physical mem to be based on the memory available.

Ah, thanks for tracking this down! I think the problem is the usual
"available" memory does not really mean what people think it means. :/
And I unfortunately missed that (even thought I was aware of it) when
reviewing the patch.

Attached is something I just quickly prepared, which I'll clean up and
merge for the upcoming 1.21.10. Let me know if that solves the issue
for you, otherwise we'd need to look for further changes.

Thanks,
Guillem
diff --git i/lib/dpkg/compress.c w/lib/dpkg/compress.c
index 8cfba80cc..7f9345186 100644
--- i/lib/dpkg/compress.c
+++ w/lib/dpkg/compress.c
@@ -605,8 +605,14 @@ filter_lzma_error(struct io_lzma *io, lzma_ret ret)
  * page cache may be purged, not everything will be reclaimed that might be
  * reclaimed, watermarks are considered.
  */
-static const char str_MemAvailable[] = "MemAvailable";
-static const size_t len_MemAvailable = sizeof(str_MemAvailable) - 1;
+
+struct mem_field {
+	const char *name;
+	ssize_t len;
+	int tag;
+	uint64_t *var;
+};
+#define MEM_FIELD(name, tag, var) name, sizeof(name) - 1, tag, &var
 
 static int
 get_avail_mem(uint64_t *val)
@@ -615,6 +621,15 @@ get_avail_mem(uint64_t *val)
 	char *str;
 	ssize_t bytes;
 	int fd;
+	uint64_t mem_total, mem_free, mem_buffers, mem_cached;
+	struct mem_field fields[] = {
+		{ MEM_FIELD("MemTotal", 0x1, mem_total) },
+		{ MEM_FIELD("MemFree", 0x2, mem_free) },
+		{ MEM_FIELD("Buffers", 0x4, mem_buffers) },
+		{ MEM_FIELD("Cached", 0x8, mem_cached) },
+	};
+	const int want_tags = 0xf;
+	int seen_tags = 0;
 
 	*val = 0;
 
@@ -632,14 +647,23 @@ get_avail_mem(uint64_t *val)
 
 	str = buf;
 	while (1) {
+		struct mem_field *field = NULL;
 		char *end;
+		size_t f;
 
 		end = strchr(str, ':');
 		if (end == 0)
 			break;
 
-		if ((end - str) == len_MemAvailable &&
-		    strncmp(str, str_MemAvailable, len_MemAvailable) == 0) {
+		for (f = 0; f < array_count(fields); f++) {
+			if ((end - str) == fields[f].len &&
+			    strncmp(str, fields[f].name, fields[f].len) == 0) {
+				field = &fields[f];
+				break;
+			}
+		}
+
+		if (field) {
 			intmax_t num;
 
 			str = end + 1;
@@ -657,16 +681,25 @@ get_avail_mem(uint64_t *val)
 			/* This should not overflow, but just in case. */
 			if (num < (INTMAX_MAX / 1024))
 				num *= 1024;
-			*val = num;
-			return 0;
+
+			*field->var = num;
+			seen_tags |= field->tag;
 		}
 
+		if (seen_tags == want_tags)
+			break;
+
 		end = strchr(end + 1, '\n');
 		if (end == 0)
 			break;
 		str = end + 1;
 	}
-	return -1;
+
+	if (seen_tags != want_tags)
+		return -1;
+
+	*val = mem_total - (mem_free + mem_buffers + mem_cached);
+	return 0;
 }
 # else
 static int

Reply via email to