mirror of
https://github.com/YGGverse/nexy.git
synced 2026-03-31 17:25:27 +00:00
implement index pool auto clean on limits overflow
This commit is contained in:
parent
56830be4a9
commit
9643adbe99
4 changed files with 69 additions and 19 deletions
|
|
@ -23,8 +23,11 @@ impl Session {
|
||||||
debug: Debug::init(config)?,
|
debug: Debug::init(config)?,
|
||||||
public: Public::init(config)?,
|
public: Public::init(config)?,
|
||||||
request: Request::init(
|
request: Request::init(
|
||||||
// do not init `Connection` event if its features not in use
|
// do not int request collector if its features not in use
|
||||||
template.welcome.contains("{hosts}") || template.welcome.contains("{hits}"),
|
template.welcome.contains("{hosts}")
|
||||||
|
|| template.welcome.contains("{hits}")
|
||||||
|
|| template.index.contains("{hosts}")
|
||||||
|
|| template.index.contains("{hits}"),
|
||||||
),
|
),
|
||||||
template,
|
template,
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -7,22 +7,69 @@ use std::{
|
||||||
sync::RwLock,
|
sync::RwLock,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Collect peer requests to print stats and visitors count
|
/// Collect peer requests for stats and visitors count
|
||||||
pub struct Request(Option<RwLock<HashMap<IpAddr, Vec<Query>>>>);
|
pub struct Request {
|
||||||
|
index: Option<RwLock<HashMap<IpAddr, Vec<Query>>>>,
|
||||||
|
// prevent log file overflow by recording error events once
|
||||||
|
is_max_peers_reported: RwLock<bool>,
|
||||||
|
is_max_peer_queries_reported: RwLock<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
impl Request {
|
impl Request {
|
||||||
pub fn init(is_enabled: bool) -> Self {
|
pub fn init(is_enabled: bool) -> Self {
|
||||||
if is_enabled {
|
Self {
|
||||||
Self(Some(RwLock::new(HashMap::with_capacity(100))))
|
index: if is_enabled {
|
||||||
|
Some(RwLock::new(HashMap::with_capacity(100)))
|
||||||
} else {
|
} else {
|
||||||
Self(None)
|
None
|
||||||
|
},
|
||||||
|
is_max_peers_reported: RwLock::new(false),
|
||||||
|
is_max_peer_queries_reported: RwLock::new(false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(&self, peer: &SocketAddr, query: &str) {
|
pub fn add(&self, peer: &SocketAddr, query: &str) {
|
||||||
if let Some(ref this) = self.0 {
|
if let Some(ref this) = self.index {
|
||||||
this.write()
|
let mut index = this.write().unwrap();
|
||||||
.unwrap()
|
|
||||||
|
// Critical limits to forcefully free one memory slot(s) for the new record
|
||||||
|
// * the query len is already limited by the read buffer (1024 bytes * LIMIT)
|
||||||
|
// * make it optional @TODO
|
||||||
|
const INDEX_MAX_PEERS: usize = 1000;
|
||||||
|
const INDEX_MAX_PEER_QUERIES: usize = 1000;
|
||||||
|
|
||||||
|
if index.len() >= INDEX_MAX_PEERS {
|
||||||
|
let mut r = self.is_max_peers_reported.write().unwrap();
|
||||||
|
if !*r {
|
||||||
|
*r = true;
|
||||||
|
eprintln!("Max peers index limit ({INDEX_MAX_PEERS}) reached");
|
||||||
|
}
|
||||||
|
let k = *index.keys().next().unwrap();
|
||||||
|
index.remove(&k); // * there is no difference which one key to free for the HashMap
|
||||||
|
}
|
||||||
|
for queries in index.values_mut() {
|
||||||
|
if queries.len() >= INDEX_MAX_PEER_QUERIES {
|
||||||
|
let mut r = self.is_max_peer_queries_reported.write().unwrap();
|
||||||
|
if !*r {
|
||||||
|
*r = true;
|
||||||
|
eprintln!(
|
||||||
|
"Max queries limit ({INDEX_MAX_PEER_QUERIES}) reached for `{peer}`"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
queries.truncate(INDEX_MAX_PEER_QUERIES - 1) // free last slot for one query
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup deprecated records
|
||||||
|
// * this is expensive for each request, use schedule instead @TODO
|
||||||
|
let d = chrono::Local::now().date_naive();
|
||||||
|
for queries in index.values_mut() {
|
||||||
|
queries.retain(|q| q.time.date_naive() == d)
|
||||||
|
}
|
||||||
|
index.retain(|_, q| !q.is_empty());
|
||||||
|
|
||||||
|
// handle new record
|
||||||
|
index
|
||||||
.entry(peer.ip())
|
.entry(peer.ip())
|
||||||
.and_modify(|c| c.push(Query::new(query)))
|
.and_modify(|c| c.push(Query::new(query)))
|
||||||
.or_insert(vec![Query::new(query)]);
|
.or_insert(vec![Query::new(query)]);
|
||||||
|
|
@ -30,8 +77,8 @@ impl Request {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn count(&self) -> usize {
|
pub fn count(&self) -> usize {
|
||||||
if let Some(ref this) = self.0 {
|
if let Some(ref i) = self.index {
|
||||||
this.read().unwrap().len()
|
i.read().unwrap().len()
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
@ -39,8 +86,8 @@ impl Request {
|
||||||
|
|
||||||
pub fn total(&self, query_prefix: Option<&str>) -> usize {
|
pub fn total(&self, query_prefix: Option<&str>) -> usize {
|
||||||
let mut t = 0;
|
let mut t = 0;
|
||||||
if let Some(ref this) = self.0 {
|
if let Some(ref i) = self.index {
|
||||||
for queries in this.read().unwrap().values() {
|
for queries in i.read().unwrap().values() {
|
||||||
match query_prefix {
|
match query_prefix {
|
||||||
Some(p) => {
|
Some(p) => {
|
||||||
for q in queries {
|
for q in queries {
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
use std::time::SystemTime;
|
use chrono::{DateTime, Local};
|
||||||
|
|
||||||
pub struct Query {
|
pub struct Query {
|
||||||
pub time: SystemTime,
|
pub time: DateTime<Local>,
|
||||||
pub value: String,
|
pub value: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Query {
|
impl Query {
|
||||||
pub fn new(value: &str) -> Self {
|
pub fn new(value: &str) -> Self {
|
||||||
Self {
|
Self {
|
||||||
time: SystemTime::now(),
|
time: Local::now(),
|
||||||
value: value.to_string(),
|
value: value.to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
pub struct Template {
|
pub struct Template {
|
||||||
access_denied: Vec<u8>,
|
access_denied: Vec<u8>,
|
||||||
index: String,
|
|
||||||
internal_server_error: Vec<u8>,
|
internal_server_error: Vec<u8>,
|
||||||
not_found: Vec<u8>,
|
not_found: Vec<u8>,
|
||||||
|
pub index: String,
|
||||||
pub welcome: String,
|
pub welcome: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue