Appendix: Implementing Database level garbage collection for Blobs
Benchmark Source
server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define BACKLOG 100
void panic(int code, int lineNum) {
if (code == 0) {
return;
}
char error_msg[64];
snprintf(error_msg, sizeof(error_msg), "Panic %d @ %d\n", code, lineNum);
__attribute__((unused)) ssize_t bytes_written = write(STDOUT_FILENO, error_msg, strlen(error_msg));
exit(code);
}
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int addrlen = sizeof(address);
// Create socket
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
panic(255, 31);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(8080);
// Bind socket to address and port
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
panic(1, 44);
}
// Listen for incoming connections
if (listen(server_fd, BACKLOG) < 0) {
panic(1, 56);
}
while (1) {
// Accept incoming connection
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
panic(1, 69);
}
// Send HTTP response
const char *response = "HTTP/1.1 200 OK\r\n\r\nHello, World!";
ssize_t send_result = send(new_socket, response, strlen(response), 0);
if (send_result < 0) {
panic(1, 93);
}
// Shutdown and close the socket
shutdown(new_socket, SHUT_RDWR);
close(new_socket);
}
return 0;
}
server.wat
(module
(type (;0;) (func (param i32) (result i32)))
(type (;1;) (func (param i32 i32) (result i32)))
(type (;2;) (func (param i32 i32 i32) (result i32)))
(type (;3;) (func (param i32 i32 i32 i32) (result i32)))
(type (;4;) (func (param i32 i32 i32 i32 i32) (result i32)))
(type (;5;) (func))
(type (;6;) (func (param i32)))
(type (;7;) (func (param i32 i32)))
(import "wasix_32v1" "fd_write" (func (;0;) (type 3)))
(import "wasix_32v1" "fd_close" (func (;1;) (type 0)))
(import "wasix_32v1" "sock_open" (func (;2;) (type 3)))
(import "wasix_32v1" "sock_bind" (func (;3;) (type 1)))
(import "wasix_32v1" "sock_listen" (func (;4;) (type 1)))
(import "wasix_32v1" "sock_accept_v2" (func (;5;) (type 3)))
(import "wasix_32v1" "sock_send" (func (;6;) (type 4)))
(import "wasix_32v1" "sock_status" (func (;7;) (type 1)))
(import "wasix_32v1" "proc_exit" (func (;8;) (type 6)))
(import "wasix_32v1" "sock_shutdown" (func (;9;) (type 1)))
;; main()
(func (;10;) (type 5) (local i32 i32)
;; Create socket using sock_open
i32.const 1 ;; PF_NET
i32.const 1 ;; SOCK_STREAM
i32.const 0 ;; Protocol
i32.const 255 ;; result pointer
call 2 ;; sock_open()
;; panic on error @
i32.const 31
call 11
;; Load the socket descriptor from memory
i32.const 255
i32.load
local.set 0
;; Bind socket to address and port
local.get 0 ;; Socket file descriptor
i32.const 48 ;; Address of the sockaddr_in structure
call 3 ;; sock_bind()
;; panic on error @
i32.const 44
call 11
local.get 0
call 13 ;; sock_status_print()
drop
;; Listen for incoming connections
local.get 0 ;; Socket file descriptor
i32.const 100 ;; Backlog (maximum pending connections)
call 4 ;; sock_listen()
;; panic on error @
i32.const 56
call 11
local.get 0
call 13 ;; sock_status_print()
drop
(loop
local.get 0 ;; Listening socket file descriptor
i32.const 0 ;; Desired file descriptor flags (default)
i32.const 64 ;; result pointer: new socket
i32.const 160 ;; result pointer: remote address
call 5 ;; sock_accept_v2()
;; panic on error @
i32.const 69
call 11
;; Load the new socket descriptor from memory
i32.const 64
i32.load
local.set 1
;; Send response to the client
local.get 1 ;; socket
i32.const 80 ;; iovs
i32.const 1 ;; iovs_len
i32.const 0 ;; No additional flags
i32.const 160 ;; ptr: remote address
call 6 ;; sock_send()
;; panic on error @
i32.const 93
call 11
;; Shutdown the socket
local.get 1 ;; socket
i32.const 2 ;; how: SHUT_RDWR
call 9 ;; sock_shutdown()
drop
;; Close the fd
local.get 1 ;; socket
call 1 ;; fd_close()
drop
br 0
)
)
;; panicOnError(code: i32, lineNum: i32)
(func (;11;) (type 7) (param i32 i32)
local.get 0
i32.const 0
i32.eq
if
return
end
;; overwrite string encoding param.0
i32.const 14
local.get 0
i32.const 100
i32.div_u
i32.const 2
call 12
i32.store8
i32.const 15
local.get 0
i32.const 10
i32.div_u
i32.const 1
call 12
i32.store8
i32.const 16
local.get 0
i32.const 0
call 12
i32.store8
;; overwrite string encoding param.1
i32.const 20
local.get 1
i32.const 100
i32.div_u
i32.const 2
call 12
i32.store8
i32.const 21
local.get 1
i32.const 10
i32.div_u
i32.const 1
call 12
i32.store8
i32.const 22
local.get 1
i32.const 0
call 12
i32.store8
;; write to buffer
i32.const 1 ;; std.io file descriptor
i32.const 0 ;; iovs
i32.const 1 ;; iovs_len
i32.const 255 ;; nwritten
call 0 ;; fd_write
drop
local.get 0
call 8
)
;; digitToChar(num: i32, place: i32)
(func (;12;) (type 1) (param i32 i32) (result i32) (local i32)
local.get 0
i32.const 10
i32.rem_u
local.set 2
local.get 1
i32.const 0
i32.ne
if
local.get 2
i32.const 0
i32.eq
if
i32.const 95
return
end
end
local.get 2
i32.const 48
i32.add
return
)
;; sock_status_print(fd: i32)
(func (;13;) (type 0) (param i32) (result i32) (local i32)
local.get 0 ;; socket
i32.const 255 ;; ptr: status
call 7 ;; sock_status()
;; panic on error @
i32.const 185
call 11
i32.const 255
i32.load
local.set 1
;; overwrite string encoding
i32.const 145
local.get 1
i32.const 100
i32.div_u
i32.const 2
call 12
i32.store8
i32.const 146
local.get 1
i32.const 10
i32.div_u
i32.const 1
call 12
i32.store8
i32.const 147
local.get 1
i32.const 0
call 12
i32.store8
;; write to buffer
i32.const 1 ;; std.io file descriptor
i32.const 124 ;; iovs
i32.const 1 ;; iovs_len
i32.const 255 ;; nwritten
call 0 ;; fd_write
drop
local.get 1
return
)
;; sock_wait_opened(fd: i32)
(func (;14;) (type 6) (param i32)
block
loop
local.get 0
call 13 ;; sock_status_print()
i32.const 0
i32.ne
if
br 2
end
br 0
end
end
)
(memory (;0;) 1)
(export "memory" (memory 0))
(export "_start" (func 10))
(data (i32.const 0) "\08\00\00\00\10\00\00\00")
(data (i32.const 8) "Panic ??? @ ???\0a")
;; sockaddr_in
(data (i32.const 48) "\01\00") ;; sin_family: AF_INET = 0x0001
(data (i32.const 50) "\90\1f") ;; sin_port: 8080 = 0x1F90
(data (i32.const 52) "\00\00\00\00") ;; sin_addr:INADDR_ANY = 0.0.0.0
(data (i32.const 56) "\00\00\00\00\00\00\00\00") ;; sin_zero = char[8] padding for sockaddr compatibility
;; http response
(data (i32.const 80) "\58\00\00\00\24\00\00\00")
(data (i32.const 88) "HTTP/1.1 200 OK\0d\0a\0d\0aHello, World!")
(data (i32.const 124) "\84\00\00\00\14\00\00\00")
(data (i32.const 132) "Sock Status: ???\0d\0a")
;; global: remote sock_addr
(data (i32.const 160) "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00")
;; stack: offset.255
)
Raw Results
WebAssembly (wasmer runtime)
wasmer server.wasm --net
Running 10s test @ http://127.0.0.1:8080
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 26.55ms 128.64ms 1.77s 95.69%
Req/Sec 1.99k 1.30k 29.42k 83.84%
236457 requests in 10.10s, 8.12MB read
Socket errors: connect 0, read 236457, write 0, timeout 37
Requests/sec: 23413.55
Transfer/sec: 823.16KB
Running 10s test @ http://127.0.0.1:8080
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 10.13ms 73.05ms 1.76s 98.36%
Req/Sec 1.92k 1.18k 6.46k 65.69%
226805 requests in 10.07s, 7.79MB read
Socket errors: connect 0, read 226805, write 0, timeout 12
Requests/sec: 22533.68
Transfer/sec: 792.23KB
Running 10s test @ http://127.0.0.1:8080
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 13.71ms 83.90ms 1.77s 97.23%
Req/Sec 2.03k 1.34k 18.36k 72.21%
236314 requests in 10.10s, 8.11MB read
Socket errors: connect 0, read 236315, write 0, timeout 19
Requests/sec: 23397.43
Transfer/sec: 822.60KB
WebAssembly (wasmer llvm)
wat2wasm server.wat -o server.wasm
wasmer create-exe --llvm server.wasm -o server.out
Running 10s test @ http://127.0.0.1:8080
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 20.35ms 117.18ms 1.77s 96.60%
Req/Sec 2.51k 1.77k 34.89k 80.43%
299600 requests in 10.10s, 10.29MB read
Socket errors: connect 0, read 299600, write 0, timeout 39
Requests/sec: 29665.16
Transfer/sec: 1.02MB
Running 10s test @ http://127.0.0.1:8080
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 17.29ms 106.60ms 1.76s 97.06%
Req/Sec 2.50k 1.29k 14.02k 77.21%
301093 requests in 10.10s, 10.34MB read
Socket errors: connect 0, read 301093, write 0, timeout 23
Requests/sec: 29811.75
Transfer/sec: 1.02MB
Running 10s test @ http://127.0.0.1:8080
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 22.95ms 123.38ms 1.77s 96.22%
Req/Sec 2.47k 1.64k 36.88k 84.55%
296337 requests in 10.10s, 10.17MB read
Socket errors: connect 0, read 296337, write 0, timeout 30
Requests/sec: 29339.53
Transfer/sec: 1.01MB
Winter.js (wasmer runtime)
Running 10s test @ http://127.0.0.1:8080
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 55.14ms 8.91ms 165.95ms 93.45%
Req/Sec 396.56 138.06 680.00 62.94%
47648 requests in 10.05s, 5.47MB read
Requests/sec: 4740.14
Transfer/sec: 556.95KB
Running 10s test @ http://127.0.0.1:8080
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 50.93ms 6.07ms 215.99ms 84.28%
Req/Sec 200.83 106.82 686.00 68.49%
24136 requests in 10.04s, 2.77MB read
Requests/sec: 2403.87
Transfer/sec: 282.71KB
Running 10s test @ http://127.0.0.1:8080
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 52.97ms 9.61ms 251.05ms 90.47%
Req/Sec 112.27 79.62 400.00 65.18%
13092 requests in 10.04s, 1.50MB read
Requests/sec: 1304.06
Transfer/sec: 153.45KB
Node
Running 10s test @ http://127.0.0.1:8080
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 45.82ms 177.25ms 1.99s 95.62%
Req/Sec 2.88k 835.90 11.15k 90.74%
325385 requests in 10.03s, 53.37MB read
Socket errors: connect 0, read 0, write 0, timeout 43
Requests/sec: 32447.16
Transfer/sec: 5.32MB
Running 10s test @ http://127.0.0.1:8080
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 45.24ms 171.77ms 2.00s 95.86%
Req/Sec 2.49k 816.56 11.11k 90.42%
280164 requests in 10.06s, 45.96MB read
Socket errors: connect 0, read 0, write 0, timeout 64
Requests/sec: 27851.09
Transfer/sec: 4.57MB
Running 10s test @ http://127.0.0.1:8080
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 43.95ms 168.63ms 1.99s 95.99%
Req/Sec 2.51k 0.88k 17.13k 90.40%
283702 requests in 10.06s, 46.54MB read
Socket errors: connect 0, read 0, write 0, timeout 60
Requests/sec: 28193.25
Transfer/sec: 4.62MB
Bun
Running 10s test @ http://127.0.0.1:8080
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 3.21ms 1.11ms 40.54ms 97.62%
Req/Sec 10.44k 699.00 16.63k 85.83%
1254427 requests in 10.06s, 143.56MB read
Requests/sec: 124727.81
Transfer/sec: 14.27MB
Running 10s test @ http://127.0.0.1:8080
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 3.48ms 362.15us 11.16ms 80.94%
Req/Sec 9.52k 506.77 18.89k 94.37%
1143770 requests in 10.06s, 130.89MB read
Requests/sec: 113749.38
Transfer/sec: 13.02MB
Running 10s test @ http://127.0.0.1:8080
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 3.14ms 382.54us 8.30ms 84.57%
Req/Sec 10.57k 786.85 20.00k 97.35%
1268543 requests in 10.02s, 145.17MB read
Requests/sec: 126545.76
Transfer/sec: 14.48MB
C (gcc -O0)
Running 10s test @ http://127.0.0.1:8080
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 21.26ms 117.42ms 1.77s 95.95%
Req/Sec 4.73k 2.65k 16.46k 72.86%
562425 requests in 10.10s, 17.16MB read
Socket errors: connect 0, read 562425, write 0, timeout 36
Requests/sec: 55685.12
Transfer/sec: 1.70MB
Running 10s test @ http://127.0.0.1:8080
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 27.25ms 143.89ms 1.77s 95.87%
Req/Sec 4.85k 2.46k 17.69k 66.83%
579112 requests in 10.10s, 17.67MB read
Socket errors: connect 0, read 579112, write 0, timeout 35
Requests/sec: 57339.04
Transfer/sec: 1.75MB
Running 10s test @ http://127.0.0.1:8080
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 26.16ms 124.31ms 1.77s 95.02%
Req/Sec 4.84k 2.82k 34.01k 75.42%
574902 requests in 10.10s, 17.55MB read
Socket errors: connect 0, read 574902, write 0, timeout 32
Requests/sec: 56920.29
Transfer/sec: 1.74MB
C (gcc -O3)
Running 10s test @ http://127.0.0.1:8080
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 18.98ms 115.87ms 1.76s 96.51%
Req/Sec 5.00k 2.96k 29.10k 74.96%
594236 requests in 10.10s, 18.13MB read
Socket errors: connect 0, read 594236, write 0, timeout 28
Requests/sec: 58834.45
Transfer/sec: 1.80MB
Running 10s test @ http://127.0.0.1:8080
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 20.99ms 119.09ms 1.77s 96.18%
Req/Sec 5.00k 2.87k 24.91k 74.08%
594872 requests in 10.10s, 18.15MB read
Socket errors: connect 0, read 594872, write 0, timeout 43
Requests/sec: 58899.79
Transfer/sec: 1.80MB
Running 10s test @ http://127.0.0.1:8080
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 21.32ms 125.58ms 1.77s 96.48%
Req/Sec 5.15k 3.13k 18.28k 71.01%
597622 requests in 10.10s, 18.24MB read
Socket errors: connect 0, read 597622, write 0, timeout 47
Requests/sec: 59175.08
Transfer/sec: 1.81MB