Skip to content
This repository was archived by the owner on Mar 24, 2026. It is now read-only.

Commit 3609ee8

Browse files
committed
update to new version of water_http
1 parent 654871f commit 3609ee8

11 files changed

Lines changed: 386 additions & 289 deletions

File tree

frameworks/Rust/water-http/Cargo.toml

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@ edition = "2024"
55

66
[dependencies]
77
askama = "0.14.0"
8-
tokio = { version = "1.47.1", features = ["full"] }
9-
water_http = { features = ["use_io_uring","use_only_http1"],optional = true , version = "3.4.2-beta.4" }
8+
tokio = { version = "1.48.0", features = ["full"] }
9+
10+
water_http = { features = ["use_only_http1"],optional = true , version = "4.0.1-beta.89",git = "https://github.com/HassanSharara/water_http", rev = "78c9859"}
11+
#water_http_unrealistic = {package = "water_http" ,features = ["use_io_uring","use_only_http1"],optional = true , version = "3.4.2-beta.4" }
12+
1013
smallvec = "1.15.1"
1114
nanorand = "0.8.0"
1215
tokio-postgres = "0.7.15"
@@ -19,6 +22,12 @@ httpdate = "1.0.3"
1922
parking_lot = "0.12.5"
2023
yarte = { version = "0.15.7" ,features = ["bytes-buf", "json"] }
2124
itoa = {version = "1.0.15" ,optional = true}
25+
smallbox = "0.8.8"
26+
mimalloc = "0.1.48"
27+
xitca-postgres = "0.4.0"
28+
#chopin-pg = "0.5.18"
29+
water_buffer = {version = "1.2.9",features = ["bytes","unsafe_clone"]}
30+
integer_to_bytes = "0.2.2"
2231

2332

2433
[[bin]]
@@ -42,4 +51,14 @@ required-features = ["cache"]
4251
json_plaintext = ["water_http"]
4352
db = ["water_http/thread_shared_struct"]
4453
cache = ["water_http/thread_shared_struct","itoa"]
45-
all = ["water_http/thread_shared_struct"]
54+
all = ["water_http","water_http/thread_shared_struct","water_http/cpu_affinity"]
55+
uring = ["water_http","water_http/thread_shared_struct", "water_http/use_io_uring"]
56+
57+
[profile.release]
58+
opt-level = 3
59+
codegen-units = 1
60+
panic = 'abort'
61+
lto = "fat"
62+
debug = false
63+
incremental = false
64+
overflow-checks = false

frameworks/Rust/water-http/benchmark_config.json

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11

22
{
33
"framework": "water-http",
4-
"maintainers" : ["HassanSharara"],
54
"tests": [
65
{
7-
"default": {
6+
"default": {
87
"json_url": "/json",
98
"plaintext_url": "/plaintext",
109
"fortune_url": "/fortunes",
1110
"db_url": "/db",
1211
"query_url": "/queries?q=",
1312
"update_url": "/updates?q=",
14-
"cached_query_url": "/cached-queries?q=",
1513
"port": 8080,
1614
"approach": "Stripped",
1715
"classification": "Fullstack",
@@ -25,6 +23,50 @@
2523
"database_os": "Linux",
2624
"display_name": "water_http",
2725
"tags": []
26+
},
27+
28+
29+
30+
"unstable": {
31+
"json_url": "/json",
32+
"plaintext_url": "/plaintext",
33+
"fortune_url": "/fortunes",
34+
"db_url": "/db",
35+
"query_url": "/queries?q=",
36+
"update_url": "/updates?q=",
37+
"port": 8080,
38+
"approach": "Realistic",
39+
"classification": "Fullstack",
40+
"database": "Postgres",
41+
"framework": "water_http",
42+
"language": "Rust",
43+
"orm": "raw",
44+
"platform": "Rust",
45+
"webserver": "water_http",
46+
"os": "Linux",
47+
"database_os": "Linux",
48+
"display_name": "water_http [uns]"
49+
},
50+
51+
"uring": {
52+
"json_url": "/json",
53+
"plaintext_url": "/plaintext",
54+
"fortune_url": "/fortunes",
55+
"db_url": "/db",
56+
"query_url": "/queries?q=",
57+
"update_url": "/updates?q=",
58+
"port": 8080,
59+
"approach": "Realistic",
60+
"classification": "Fullstack",
61+
"database": "Postgres",
62+
"framework": "water_http",
63+
"language": "Rust",
64+
"orm": "raw",
65+
"platform": "Rust",
66+
"webserver": "water_http",
67+
"os": "Linux",
68+
"database_os": "Linux",
69+
"display_name": "water_http [io-uring]"
2870
}
2971
}
3072
]
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
use std::cell::RefCell;
2+
use crate::models::Fortune;
3+
// Assuming water_buffer crate exists
4+
// use water_buffer::WaterBuffer as BM;
5+
6+
// Mocking the type for compilation demo
7+
type WaterBuffer = Vec<u8>;
8+
9+
const INITIAL_VEC_CAPACITY: usize = 128;
10+
const DEFAULT_SIZE: usize = 4048;
11+
const MAX_BUFFER_SIZE: usize = 8192; // Allow some growth before discarding
12+
const MAX_CACHED_BUFFERS: usize = 117; // Set to your test requirement
13+
14+
thread_local! {
15+
static BUFFER_CACHE: RefCell<Vec<WaterBuffer>> = RefCell::new(Vec::with_capacity(INITIAL_VEC_CAPACITY));
16+
static FORTUNE_CACHE: RefCell<Vec<Vec<Fortune>>> = RefCell::new(Vec::with_capacity(INITIAL_VEC_CAPACITY));
17+
}
18+
19+
pub struct PooledBuffer {
20+
inner: Option<WaterBuffer>,
21+
}
22+
23+
pub struct FortunesPool {
24+
inner: Option<Vec<Fortune>>,
25+
}
26+
27+
28+
impl PooledBuffer {
29+
pub fn new() -> Self {
30+
Self::with_capacity(DEFAULT_SIZE)
31+
}
32+
33+
pub fn with_capacity(cap: usize) -> Self {
34+
let buf = BUFFER_CACHE.with(|cache| {
35+
let mut cache = cache.borrow_mut();
36+
if let Some(mut existing_buf) = cache.pop() {
37+
// Assuming your WaterBuffer has a clear/reset method
38+
existing_buf.clear();
39+
existing_buf
40+
} else {
41+
// Fallback to new allocation if cache is empty
42+
WaterBuffer::with_capacity(cap)
43+
}
44+
});
45+
46+
Self { inner: Some(buf) }
47+
}
48+
49+
pub fn take_inner(&mut self) -> WaterBuffer {
50+
self.inner.take().expect("Buffer already taken or dropped")
51+
}
52+
53+
pub fn recycle(buf: WaterBuffer) {
54+
// Use capacity() check to ensure we don't cache
55+
// a buffer that grew to a massive size during one specific request
56+
if buf.capacity() <= MAX_BUFFER_SIZE {
57+
BUFFER_CACHE.with(|cache| {
58+
let mut cache = cache.borrow_mut();
59+
if cache.len() < MAX_CACHED_BUFFERS {
60+
cache.push(buf);
61+
}
62+
});
63+
}
64+
}
65+
}
66+
impl FortunesPool {
67+
pub fn new() -> Self {
68+
Self::with_capacity(16)
69+
}
70+
71+
pub fn with_capacity(cap: usize) -> Self {
72+
let buf = FORTUNE_CACHE.with(|cache| {
73+
let mut cache = cache.borrow_mut();
74+
if let Some(mut existing_buf) = cache.pop() {
75+
// Assuming your WaterBuffer has a clear/reset method
76+
existing_buf.clear();
77+
existing_buf
78+
} else {
79+
// Fallback to new allocation if cache is empty
80+
Vec::with_capacity(cap)
81+
}
82+
});
83+
84+
Self { inner: Some(buf) }
85+
}
86+
87+
pub fn take_inner(&mut self) -> Vec<Fortune> {
88+
self.inner.take().expect("Buffer already taken or dropped")
89+
}
90+
91+
pub fn recycle(buf: WaterBuffer) {
92+
// Use capacity() check to ensure we don't cache
93+
// a buffer that grew to a massive size during one specific request
94+
if buf.capacity() <= 16 {
95+
BUFFER_CACHE.with(|cache| {
96+
let mut cache = cache.borrow_mut();
97+
if cache.len() < 2000 {
98+
cache.push(buf);
99+
}
100+
});
101+
}
102+
}
103+
}
104+

frameworks/Rust/water-http/src/cached.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
#![allow(static_mut_refs)]
2+
3+
24
use std::io;
35
use std::fmt::Arguments;
46
use std::io::Write;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
use std::cell::UnsafeCell;
2+
use std::time::{SystemTime, UNIX_EPOCH};
3+
4+
thread_local! {
5+
// We store the bytes directly in the Thread Local Storage (TLS)
6+
// to ensure the reference stays valid for the life of the thread.
7+
static CACHED_DATE: UnsafeCell<(u64, [u8; 29])> = UnsafeCell::new((0, [0u8; 29]));
8+
}
9+
10+
#[inline(always)]
11+
pub fn get_date_fast() -> &'static str {
12+
CACHED_DATE.with(|cell| {
13+
unsafe {
14+
let cache = &mut *cell.get();
15+
// 1. Use a fast duration check
16+
let now = SystemTime::now()
17+
.duration_since(UNIX_EPOCH)
18+
.unwrap_unchecked() // Benchmark trick: avoid panic branches
19+
.as_secs();
20+
21+
if now != cache.0 {
22+
cache.0 = now;
23+
let date_str = httpdate::fmt_http_date(SystemTime::now());
24+
cache.1.copy_from_slice(date_str.as_bytes());
25+
}
26+
27+
// 2. Return a reference to the TLS memory directly.
28+
// This is safe because the thread never dies during the benchmark.
29+
std::str::from_utf8_unchecked(&cache.1)
30+
}
31+
})
32+
}

0 commit comments

Comments
 (0)