aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2026-02-18 16:08:34 +0100
committermetamuffin <metamuffin@disroot.org>2026-02-18 16:08:34 +0100
commit70169924b611b9b68587bd9169f991e3770b7dc7 (patch)
tree83268ed2da5526d50ef111f8d7217b908221da6d
parent45a485431df0638396f0175de59275b3b5538022 (diff)
downloadjellything-70169924b611b9b68587bd9169f991e3770b7dc7.tar
jellything-70169924b611b9b68587bd9169f991e3770b7dc7.tar.bz2
jellything-70169924b611b9b68587bd9169f991e3770b7dc7.tar.zst
show database debug info
-rw-r--r--common/object/src/path.rs14
-rw-r--r--common/src/api.rs3
-rw-r--r--database/src/kv/index_key.rs48
-rw-r--r--database/src/kv/mod.rs13
-rw-r--r--database/src/lib.rs1
-rw-r--r--database/src/query_ser.rs27
-rw-r--r--server/src/api.rs12
-rw-r--r--server/src/routes.rs3
-rw-r--r--server/src/ui/admin/mod.rs20
-rw-r--r--server/src/ui/home.rs4
-rw-r--r--ui/src/components/admin.rs8
-rw-r--r--ui/src/components/mod.rs5
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 }
+ }
}
}