Read complete bounded Memcached responses

This commit is contained in:
root
2026-07-20 23:24:57 +00:00
parent 0c75703186
commit 10e6565037
7 changed files with 263 additions and 19 deletions
+1
View File
@@ -13,6 +13,7 @@ return value : string containing the Memcache server's response
Executes a raw command on an open Memcache connection and returns the server response as a string.
This is the low-level escape hatch for Memcache operations that are not covered by the dedicated helpers.
UCE reads the complete framed ASCII response, including multi-value retrievals and `stats`, rather than returning a socket chunk. The complete write and read share a one-second deadline and responses are limited to 8 MiB. A timeout, malformed frame, or oversized response returns an empty string and makes that connection unusable so unread bytes cannot affect a later command. Commands ending in `noreply` and `quit` return immediately with an empty string.
:example
u64 conn = memcache_connect();
+17 -2
View File
@@ -90,10 +90,25 @@ RENDER(Request& context)
StringMap mem_multi = memcache_get_multiple(memfd, {"site-tests-key", "site-tests-key2"});
memcache_delete(memfd, "site-tests-key");
memcache_delete(memfd, "site-tests-key2");
String large_mem_value(200 * 1024, 'x');
large_mem_value.replace(1024, 7, "\r\nEND\r\n");
bool large_mem_stored = memcache_set(memfd, "site-tests-large", large_mem_value);
String large_mem_loaded = memcache_get(memfd, "site-tests-large");
String second_large_mem_value(160 * 1024, 'y');
bool second_large_mem_stored = memcache_set(memfd, "site-tests-large-2", second_large_mem_value);
StringMap large_mem_multi = memcache_get_multiple(memfd, {"site-tests-large", "site-tests-large-2"});
String no_reply = memcache_command(memfd, "set site-tests-noreply 0 60 5 noreply\r\nvalue");
String no_reply_value = memcache_get(memfd, "site-tests-noreply");
String stats_mem = memcache_command(memfd, "stats");
String stats_reset_mem = memcache_command(memfd, "stats reset");
String after_stats_reset = memcache_get(memfd, "site-tests-noreply");
bool large_mem_deleted = memcache_delete(memfd, "site-tests-large");
bool second_large_mem_deleted = memcache_delete(memfd, "site-tests-large-2");
bool no_reply_deleted = memcache_delete(memfd, "site-tests-noreply");
mark(
"memcache_connect() / memcache_command() / memcache_get_multiple()",
mem_value == "value-1" && contains(raw_mem, "VALUE site-tests-key") && mem_multi["site-tests-key"] == "value-1" && mem_multi["site-tests-key2"] == "value-2" ? "pass" : "fail",
"memcache value=" + mem_value + " raw=" + raw_mem + " multi=" + var_dump(mem_multi)
mem_value == "value-1" && contains(raw_mem, "VALUE site-tests-key") && mem_multi["site-tests-key"] == "value-1" && mem_multi["site-tests-key2"] == "value-2" && large_mem_stored && large_mem_loaded == large_mem_value && second_large_mem_stored && large_mem_multi["site-tests-large"] == large_mem_value && large_mem_multi["site-tests-large-2"] == second_large_mem_value && no_reply == "" && no_reply_value == "value" && contains(stats_mem, "STAT ") && trim(stats_reset_mem) == "RESET" && after_stats_reset == "value" && large_mem_deleted && second_large_mem_deleted && no_reply_deleted ? "pass" : "fail",
"memcache value=" + mem_value + " raw=" + raw_mem + " multi=" + var_dump(mem_multi) + " large=" + std::to_string(large_mem_loaded.size()) + " multi-large=" + std::to_string(large_mem_multi["site-tests-large"].size() + large_mem_multi["site-tests-large-2"].size()) + " noreply=" + no_reply_value + " stats=" + std::to_string(stats_mem.size()) + "/" + trim(stats_reset_mem) + " after-reset=" + after_stats_reset + " deleted=" + (large_mem_deleted && second_large_mem_deleted && no_reply_deleted ? "true" : "false")
);
}