mirror of
https://github.com/YGGverse/aquatic.git
synced 2026-04-02 10:45:30 +00:00
aquatic http protocol: optimize request parsing
request-from-bytes: time: [1.5288 us 1.5362 us 1.5441 us] change: [-38.029% -37.466% -36.890%] (p = 0.00 < 0.01) Performance has improved.
This commit is contained in:
parent
87328f788d
commit
b7d5a12046
5 changed files with 1064 additions and 1024 deletions
|
|
@ -174,10 +174,12 @@ impl Request {
|
||||||
.with_context(|| "no query string")?;
|
.with_context(|| "no query string")?;
|
||||||
|
|
||||||
let mut info_hashes = Vec::new();
|
let mut info_hashes = Vec::new();
|
||||||
|
let mut opt_peer_id = None;
|
||||||
let mut data = HashMap::new();
|
let mut data = HashMap::new();
|
||||||
|
|
||||||
Self::parse_key_value_pairs_memchr(
|
Self::parse_key_value_pairs_memchr(
|
||||||
&mut info_hashes,
|
&mut info_hashes,
|
||||||
|
&mut opt_peer_id,
|
||||||
&mut data,
|
&mut data,
|
||||||
query_string
|
query_string
|
||||||
)?;
|
)?;
|
||||||
|
|
@ -232,14 +234,8 @@ impl Request {
|
||||||
};
|
};
|
||||||
|
|
||||||
let request = AnnounceRequest {
|
let request = AnnounceRequest {
|
||||||
info_hash: info_hashes.pop()
|
info_hash: info_hashes.pop().with_context(|| "no info_hash")?,
|
||||||
.with_context(|| "no info_hash")
|
peer_id: opt_peer_id.with_context(|| "no peer_id")?,
|
||||||
.and_then(deserialize_20_bytes)
|
|
||||||
.map(InfoHash)?,
|
|
||||||
peer_id: data.remove("peer_id")
|
|
||||||
.with_context(|| "no peer_id")
|
|
||||||
.and_then(deserialize_20_bytes)
|
|
||||||
.map(PeerId)?,
|
|
||||||
port,
|
port,
|
||||||
bytes_left,
|
bytes_left,
|
||||||
event,
|
event,
|
||||||
|
|
@ -250,14 +246,8 @@ impl Request {
|
||||||
|
|
||||||
Ok(Request::Announce(request))
|
Ok(Request::Announce(request))
|
||||||
} else {
|
} else {
|
||||||
let mut parsed_info_hashes = Vec::with_capacity(info_hashes.len());
|
|
||||||
|
|
||||||
for info_hash in info_hashes {
|
|
||||||
parsed_info_hashes.push(InfoHash(deserialize_20_bytes(info_hash)?));
|
|
||||||
}
|
|
||||||
|
|
||||||
let request = ScrapeRequest {
|
let request = ScrapeRequest {
|
||||||
info_hashes: parsed_info_hashes,
|
info_hashes,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Request::Scrape(request))
|
Ok(Request::Scrape(request))
|
||||||
|
|
@ -266,7 +256,8 @@ impl Request {
|
||||||
|
|
||||||
/// Seems to be somewhat faster than non-memchr version
|
/// Seems to be somewhat faster than non-memchr version
|
||||||
fn parse_key_value_pairs_memchr<'a>(
|
fn parse_key_value_pairs_memchr<'a>(
|
||||||
info_hashes: &mut Vec<SmartString<LazyCompact>>,
|
info_hashes: &mut Vec<InfoHash>,
|
||||||
|
opt_peer_id: &mut Option<PeerId>,
|
||||||
data: &mut HashMap<&'a str, SmartString<LazyCompact>>,
|
data: &mut HashMap<&'a str, SmartString<LazyCompact>>,
|
||||||
query_string: &'a str,
|
query_string: &'a str,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
|
@ -287,14 +278,17 @@ impl Request {
|
||||||
// whitelist keys to avoid having to use ddos-resistant hashmap
|
// whitelist keys to avoid having to use ddos-resistant hashmap
|
||||||
match key {
|
match key {
|
||||||
"info_hash" => {
|
"info_hash" => {
|
||||||
let value = Self::urldecode_memchr(value)?;
|
let value = Self::urldecode_20_bytes(value)?;
|
||||||
|
|
||||||
info_hashes.push(value);
|
info_hashes.push(InfoHash(value));
|
||||||
},
|
},
|
||||||
"peer_id" | "port" | "left" | "event" | "compact" | "numwant" | "key" => {
|
"peer_id" => {
|
||||||
let value = Self::urldecode_memchr(value)?;
|
let value = Self::urldecode_20_bytes(value)?;
|
||||||
|
|
||||||
data.insert(key, value);
|
*opt_peer_id = Some(PeerId(value));
|
||||||
|
},
|
||||||
|
"port" | "left" | "event" | "compact" | "numwant" | "key" => {
|
||||||
|
data.insert(key, value.into());
|
||||||
},
|
},
|
||||||
k => {
|
k => {
|
||||||
::log::info!("ignored unrecognized key: {}", k)
|
::log::info!("ignored unrecognized key: {}", k)
|
||||||
|
|
@ -386,6 +380,52 @@ impl Request {
|
||||||
Ok(processed)
|
Ok(processed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn urldecode_20_bytes(value: &str) -> anyhow::Result<[u8; 20]> {
|
||||||
|
let mut out_arr = [0u8; 20];
|
||||||
|
|
||||||
|
let mut chars = value.chars();
|
||||||
|
|
||||||
|
for i in 0..20 {
|
||||||
|
let c = chars.next()
|
||||||
|
.with_context(|| "less than 20 chars")?;
|
||||||
|
|
||||||
|
if c as u32 > 255 {
|
||||||
|
return Err(anyhow::anyhow!(
|
||||||
|
"character not in single byte range: {:#?}",
|
||||||
|
c
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if c == '%' {
|
||||||
|
let first = chars.next()
|
||||||
|
.with_context(|| "missing first urldecode char in pair")?;
|
||||||
|
let second = chars.next()
|
||||||
|
.with_context(|| "missing second urldecode char in pair")?;
|
||||||
|
|
||||||
|
let hex = [first as u8, second as u8];
|
||||||
|
|
||||||
|
hex::decode_to_slice(&hex, &mut out_arr[i..i+1]).map_err(|err|
|
||||||
|
anyhow::anyhow!("hex decode error: {:?}", err)
|
||||||
|
)?;
|
||||||
|
} else {
|
||||||
|
if c as u32 > 255 {
|
||||||
|
return Err(anyhow::anyhow!(
|
||||||
|
"character not in single byte range: {:#?}",
|
||||||
|
c
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
out_arr[i] = c as u8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if chars.next().is_some(){
|
||||||
|
return Err(anyhow::anyhow!("more than 20 chars"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(out_arr)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn as_bytes(&self) -> Vec<u8> {
|
pub fn as_bytes(&self) -> Vec<u8> {
|
||||||
match self {
|
match self {
|
||||||
Self::Announce(r) => r.as_bytes(),
|
Self::Announce(r) => r.as_bytes(),
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":2460.1209520234065,"upper_bound":2496.3120750993653},"point_estimate":2477.735012452959,"standard_error":9.223219637832466},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":2378.552109650183,"upper_bound":2392.9167858884143},"point_estimate":2386.0253054074483,"standard_error":3.7683770634335887},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":99.96596815329639,"upper_bound":120.92540240951352},"point_estimate":110.60694919175964,"standard_error":5.3506476356761885},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":2438.3485065067393,"upper_bound":2469.501606349259},"point_estimate":2453.4596391963023,"standard_error":7.977121580504992},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":251.73297824646409,"upper_bound":332.1546916341356},"point_estimate":291.46617601681515,"standard_error":20.531098767805926}}
|
{"mean":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1540.8390649054281,"upper_bound":1558.4887891210565},"point_estimate":1549.4245398703538,"standard_error":4.517692089474024},"median":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1506.8523919746872,"upper_bound":1513.8541497552624},"point_estimate":1510.1168042545828,"standard_error":1.754123550033509},"median_abs_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":45.152694401086514,"upper_bound":54.71728947836145},"point_estimate":49.43491905391041,"standard_error":2.470252770404891},"slope":{"confidence_interval":{"confidence_level":0.95,"lower_bound":1528.8205165274087,"upper_bound":1544.1141471464193},"point_estimate":1536.161119110567,"standard_error":3.9201641311296234},"std_dev":{"confidence_interval":{"confidence_level":0.95,"lower_bound":121.9529239151999,"upper_bound":162.2045693733035},"point_estimate":142.20072433991157,"standard_error":10.304640393049143}}
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
|
|
@ -1 +1 @@
|
||||||
[1795.8747498180473,2061.4607369455734,2769.6900359523097,3035.276023079836]
|
[1272.4120390677972,1377.6532072370742,1658.2963223551465,1763.5374905244237]
|
||||||
Loading…
Add table
Add a link
Reference in a new issue