diff options
| author | metamuffin <metamuffin@disroot.org> | 2026-02-18 16:08:34 +0100 |
|---|---|---|
| committer | metamuffin <metamuffin@disroot.org> | 2026-02-18 16:08:34 +0100 |
| commit | 70169924b611b9b68587bd9169f991e3770b7dc7 (patch) | |
| tree | 83268ed2da5526d50ef111f8d7217b908221da6d | |
| parent | 45a485431df0638396f0175de59275b3b5538022 (diff) | |
| download | jellything-70169924b611b9b68587bd9169f991e3770b7dc7.tar jellything-70169924b611b9b68587bd9169f991e3770b7dc7.tar.bz2 jellything-70169924b611b9b68587bd9169f991e3770b7dc7.tar.zst | |
show database debug info
| -rw-r--r-- | common/object/src/path.rs | 14 | ||||
| -rw-r--r-- | common/src/api.rs | 3 | ||||
| -rw-r--r-- | database/src/kv/index_key.rs | 48 | ||||
| -rw-r--r-- | database/src/kv/mod.rs | 13 | ||||
| -rw-r--r-- | database/src/lib.rs | 1 | ||||
| -rw-r--r-- | database/src/query_ser.rs | 27 | ||||
| -rw-r--r-- | server/src/api.rs | 12 | ||||
| -rw-r--r-- | server/src/routes.rs | 3 | ||||
| -rw-r--r-- | server/src/ui/admin/mod.rs | 20 | ||||
| -rw-r--r-- | server/src/ui/home.rs | 4 | ||||
| -rw-r--r-- | ui/src/components/admin.rs | 8 | ||||
| -rw-r--r-- | ui/src/components/mod.rs | 5 |
12 files changed, 119 insertions, 39 deletions
diff --git a/common/object/src/path.rs b/common/object/src/path.rs index fc14e6d..0751ff0 100644 --- a/common/object/src/path.rs +++ b/common/object/src/path.rs @@ -5,7 +5,7 @@ */ use crate::{Object, Tag, TypedTag}; -use std::marker::PhantomData; +use std::{fmt::Display, marker::PhantomData}; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Path(pub Vec<Tag>); @@ -36,3 +36,15 @@ impl Path { out } } + +impl Display for Path { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for (i, c) in self.0.iter().enumerate() { + if i > 0 { + write!(f, ".")?; + } + write!(f, "{c}")?; + } + Ok(()) + } +} diff --git a/common/src/api.rs b/common/src/api.rs index 13962a3..a49116a 100644 --- a/common/src/api.rs +++ b/common/src/api.rs @@ -25,9 +25,12 @@ fields! { VIEW_ACCOUNT_SET_PASSWORD: &str = b"acsp"; VIEW_ADMIN_DASHBOARD: () = b"adda"; VIEW_ADMIN_IMPORT: Object = b"adim"; + VIEW_ADMIN_INFO: Object = b"adin"; ADMIN_IMPORT_BUSY: () = b"busy"; ADMIN_IMPORT_ERROR: &str = b"erro"; // multi + ADMIN_INFO_TITLE: &str = b"aiti"; + ADMIN_INFO_TEXT: &str = b"aite"; NKU_NODE: Object = b"node"; NKU_UDATA: Object = b"udat"; diff --git a/database/src/kv/index_key.rs b/database/src/kv/index_key.rs index eab46c4..fae7d4a 100644 --- a/database/src/kv/index_key.rs +++ b/database/src/kv/index_key.rs @@ -1,3 +1,5 @@ +use std::fmt::Display; + /* This file is part of jellything (https://codeberg.org/metamuffin/jellything) which is licensed under the GNU Affero General Public License (version 3); see /COPYING. @@ -128,6 +130,52 @@ impl SortKey { } } +impl Display for IndexKey { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{} | {}", self.0, self.1) + } +} +impl Display for Binning { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for (i, b) in self.0.iter().enumerate() { + if i > 0 { + write!(f, " ")?; + } + write!(f, "{b}")?; + } + Ok(()) + } +} +impl Display for BinningComponent { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + BinningComponent::Has(path) => write!(f, "H({path})"), + BinningComponent::Match(path) => write!(f, "M({path})"), + } + } +} +impl Display for SortKey { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + SortKey::None => write!(f, "none"), + SortKey::Count => write!(f, "count"), + SortKey::Value(path, multi) => write!(f, "value({path}, {multi})"), + SortKey::Text(path) => write!(f, "text({path})"), + } + } +} +impl Display for MultiBehaviour { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(match self { + MultiBehaviour::First => "first", + MultiBehaviour::ForEach => "for_each", + MultiBehaviour::Max => "max", + MultiBehaviour::Min => "min", + MultiBehaviour::Count => "count", + }) + } +} + fn write_path(path: &Path, out: &mut Vec<u8>) { assert!(path.0.len() < 256); out.push(path.0.len() as u8); diff --git a/database/src/kv/mod.rs b/database/src/kv/mod.rs index f90f07e..257eec4 100644 --- a/database/src/kv/mod.rs +++ b/database/src/kv/mod.rs @@ -27,7 +27,7 @@ use crate::{ use anyhow::{Result, anyhow}; use jellyobject::ObjectBuffer; use log::{debug, info}; -use std::borrow::Cow; +use std::{borrow::Cow, fmt::Write}; pub type SubtreeNum = u32; @@ -132,6 +132,17 @@ impl Transaction for &mut dyn jellykv::Transaction { } Ok(total) } + + fn debug_info(&self) -> Result<String> { + let mut o = String::new(); + let rc = read_counter(*self, &T_ROW_COUNTER.to_be_bytes(), 0)?; + writeln!(o, "Row Counter: {rc}")?; + writeln!(o, "Indices:")?; + for (is, ik) in list_indices(*self)? { + writeln!(o, "\tIS={is} IK={ik}")?; + } + Ok(o) + } } fn get_or_create_index(txn: &mut dyn jellykv::Transaction, ik: &IndexKey) -> Result<SubtreeNum> { diff --git a/database/src/lib.rs b/database/src/lib.rs index ed9dc47..2ecf3c6 100644 --- a/database/src/lib.rs +++ b/database/src/lib.rs @@ -29,6 +29,7 @@ pub trait Transaction { ) -> Result<Box<dyn Iterator<Item = Result<(RowNum, Vec<u8>)>> + 'a>>; fn query_single(&mut self, query: Query) -> Result<Option<RowNum>>; fn count(&mut self, query: Query) -> Result<u64>; + fn debug_info(&self) -> Result<String>; } #[derive(Default, Clone)] diff --git a/database/src/query_ser.rs b/database/src/query_ser.rs index de62a72..d51ef64 100644 --- a/database/src/query_ser.rs +++ b/database/src/query_ser.rs @@ -4,8 +4,7 @@ Copyright (C) 2026 metamuffin <metamuffin.org> */ -use crate::{Filter, MultiBehaviour, Query, Sort, SortOrder, Value}; -use jellyobject::Path; +use crate::{Filter, MultiBehaviour, Query, Sort, SortOrder, Value, ValueSort}; impl Query { pub fn show(&self) -> String { @@ -40,9 +39,9 @@ impl Filter { .join(" OR ") ), Filter::Match(path, value) => { - format!("{} = {}", show_path(path), show_value(value)) + format!("{path} = {}", show_value(value)) } - Filter::Has(path) => show_path(path), + Filter::Has(path) => format!("{path}"), } } } @@ -50,37 +49,31 @@ impl Sort { pub fn show(&self) -> String { match self { Sort::None => "NONE".to_string(), - Sort::Value(vs) => { + Sort::Value(ValueSort { + multi, order, path, .. + }) => { format!( - "{} BY {} {}", - match vs.order { + "{} BY {} {path}", + match order { SortOrder::Ascending => "ASCENDING", SortOrder::Descending => "DESCENDING", }, - match vs.multi { + match multi { MultiBehaviour::Count => "COUNT", MultiBehaviour::First => "FIRST", MultiBehaviour::ForEach => "EACH", MultiBehaviour::Max => "MAX", MultiBehaviour::Min => "MIN", }, - show_path(&vs.path), ) } Sort::TextSearch(path, value) => { - format!("TEXT SEARCH {} = {value:?}", show_path(path),) + format!("TEXT SEARCH {path} = {value:?}") } } } } -fn show_path(path: &Path) -> String { - path.0 - .iter() - .map(|s| str::from_utf8(&s.0.to_be_bytes()).unwrap().to_string()) - .collect::<Vec<_>>() - .join(".") -} fn show_value(value: &Value) -> String { match value { Value::Tag(tag) => format!("{tag}"), diff --git a/server/src/api.rs b/server/src/api.rs index 9d16433..d83d8e3 100644 --- a/server/src/api.rs +++ b/server/src/api.rs @@ -3,9 +3,8 @@ which is licensed under the GNU Affero General Public License (version 3); see /COPYING. Copyright (C) 2026 metamuffin <metamuffin.org> */ -use super::ui::error::MyResult; -use crate::request_info::RequestInfo; -use rocket::{get, response::Redirect, serde::json::Json}; + +use rocket::{get, response::Redirect}; #[get("/api")] pub fn r_api_root() -> Redirect { @@ -37,10 +36,3 @@ pub fn r_version() -> &'static str { // Either::Right(s) // } // } - -#[get("/nodes_modified?<since>")] -pub fn r_nodes_modified_since(ri: RequestInfo<'_>, since: u64) -> MyResult<Json<Vec<String>>> { - // let nodes = get_nodes_modified_since(&session.0, since)?; - // Ok(Json(nodes)) - todo!() -} diff --git a/server/src/routes.rs b/server/src/routes.rs index b1fc52c..c9601d3 100644 --- a/server/src/routes.rs +++ b/server/src/routes.rs @@ -5,7 +5,7 @@ */ use crate::{ State, - api::{r_api_root, r_nodes_modified_since, r_version}, + api::{r_api_root, r_version}, compat::youtube::{r_youtube_channel, r_youtube_embed, r_youtube_watch}, logic::{ playersync::{PlayersyncChannels, r_playersync}, @@ -113,7 +113,6 @@ pub(super) fn build_rocket(state: Arc<State>) -> Rocket<Build> { // r_stats, r_stream, // API - r_nodes_modified_since, r_api_root, r_version, // Compat diff --git a/server/src/ui/admin/mod.rs b/server/src/ui/admin/mod.rs index 61e62a4..555b6bc 100644 --- a/server/src/ui/admin/mod.rs +++ b/server/src/ui/admin/mod.rs @@ -8,11 +8,27 @@ pub mod import; use super::error::MyResult; use crate::{request_info::RequestInfo, ui_responder::UiResponse}; -use jellycommon::{VIEW_ADMIN_DASHBOARD, jellyobject::ObjectBuffer}; +use jellycommon::{jellyobject::ObjectBuffer, *}; use rocket::get; #[get("/admin/dashboard")] pub async fn r_admin_dashboard(ri: RequestInfo<'_>) -> MyResult<UiResponse> { ri.require_admin()?; - Ok(ri.respond_ui(ObjectBuffer::new(&mut [(VIEW_ADMIN_DASHBOARD.0, &())]))) + + let mut db_debug = String::new(); + ri.state.database.transaction(&mut |txn| { + db_debug = txn.debug_info()?; + Ok(()) + })?; + + Ok(ri.respond_ui(ObjectBuffer::new(&mut [ + (VIEW_ADMIN_DASHBOARD.0, &()), + ( + VIEW_ADMIN_INFO.0, + &ObjectBuffer::new(&mut [ + (ADMIN_INFO_TITLE.0, &"Database Debug"), + (ADMIN_INFO_TEXT.0, &db_debug.as_str()), + ]), + ), + ]))) } diff --git a/server/src/ui/home.rs b/server/src/ui/home.rs index 86b6fbe..1f5ea8d 100644 --- a/server/src/ui/home.rs +++ b/server/src/ui/home.rs @@ -4,8 +4,6 @@ Copyright (C) 2026 metamuffin <metamuffin.org> */ -use std::time::Instant; - use super::error::MyResult; use crate::{request_info::RequestInfo, ui_responder::UiResponse}; use anyhow::Result; @@ -82,7 +80,6 @@ pub fn r_home(ri: RequestInfo<'_>) -> MyResult<UiResponse> { fn home_row(ri: &RequestInfo<'_>, title: &str, q: Query) -> Result<ObjectBuffer> { let mut res = ObjectBuffer::empty(); - let t = Instant::now(); ri.state.database.transaction(&mut |txn| { let rows = txn.query(q.clone())?.take(16).collect::<Result<Vec<_>>>()?; @@ -99,6 +96,5 @@ fn home_row(ri: &RequestInfo<'_>, title: &str, q: Query) -> Result<ObjectBuffer> Ok(()) })?; - eprintln!("{:?}", t.elapsed()); Ok(res) } diff --git a/ui/src/components/admin.rs b/ui/src/components/admin.rs index 831c746..e617ce3 100644 --- a/ui/src/components/admin.rs +++ b/ui/src/components/admin.rs @@ -6,9 +6,9 @@ use crate::RenderInfo; use jellycommon::{ - ADMIN_IMPORT_BUSY, ADMIN_IMPORT_ERROR, jellyobject::Object, routes::{u_admin_import, u_admin_import_post, u_admin_log}, + *, }; use jellyui_locale::tr; @@ -49,4 +49,10 @@ markup::define!( } } + AdminInfo<'a>(ri: &'a RenderInfo<'a>, data: Object<'a>) { + @let _ = ri; + h2 { @data.get(ADMIN_INFO_TITLE) } + pre { @data.get(ADMIN_INFO_TEXT) } + } + ); diff --git a/ui/src/components/mod.rs b/ui/src/components/mod.rs index 027dae8..b63fa44 100644 --- a/ui/src/components/mod.rs +++ b/ui/src/components/mod.rs @@ -16,7 +16,7 @@ pub mod stats; use crate::{ RenderInfo, components::{ - admin::{AdminDashboard, AdminImport}, + admin::{AdminDashboard, AdminImport, AdminInfo}, login::{AccountLogin, AccountLogout, AccountSetPassword}, message::Message, node_list::NodeList, @@ -52,5 +52,8 @@ define! { @if let Some(data) = view.get(VIEW_ADMIN_IMPORT) { @AdminImport { ri, data } } + @if let Some(data) = view.get(VIEW_ADMIN_INFO) { + @AdminInfo { ri, data } + } } } |