/* ** Copyright (c) 2007 D. Richard Hipp ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the Simplified BSD License (also ** known as the "2-Clause License" or "FreeBSD License".) ** This program is distributed in the hope that it will be useful, ** but without any warranty; without even the implied warranty of ** merchantability or fitness for a particular purpose. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code to implement the stat web page ** */ #include "VERSION.h" #include "config.h" #include #include "stat.h" /* ** For a sufficiently large integer, provide an alternative ** representation as MB or GB or TB. */ void bigSizeName(int nOut, char *zOut, sqlite3_int64 v){ if( v<100000 ){ sqlite3_snprintf(nOut, zOut, "%lld bytes", v); }else if( v<1000000000 ){ sqlite3_snprintf(nOut, zOut, "%lld bytes (%.1fMB)", v, (double)v/1000000.0); }else{ sqlite3_snprintf(nOut, zOut, "%lld bytes (%.1fGB)", v, (double)v/1000000000.0); } } /* ** WEBPAGE: stat ** ** Show statistics and global information about the repository. */ void stat_page(void){ i64 t, fsize; int n, m; int szMax, szAvg; const char *zDb; int brief; char zBuf[100]; login_check_credentials(); if( !g.perm.Read ){ login_needed(); return; } brief = P("brief")!=0; style_header("Repository Statistics"); if( g.perm.Admin ){ style_submenu_element("URLs", "URLs and Checkouts", "urllist"); style_submenu_element("Schema", "Repository Schema", "repo_schema"); style_submenu_element("Web-Cache", "Web-Cache Stats", "cachestat"); } @ @ if( !brief ){ @ if( n>0 ){ int a, b; Stmt q; @ @ } @ @ @ @ } @ @ @ @ @ @ @
Repository Size: fsize = file_size(g.zRepositoryName); bigSizeName(sizeof(zBuf), zBuf, fsize); @ %s(zBuf) @
Number Of Artifacts: n = db_int(0, "SELECT count(*) FROM blob"); m = db_int(0, "SELECT count(*) FROM delta"); @ %d(n) (%d(n-m) fulltext and %d(m) deltas) @
Uncompressed Artifact Size: db_prepare(&q, "SELECT total(size), avg(size), max(size)" " FROM blob WHERE size>0"); db_step(&q); t = db_column_int64(&q, 0); szAvg = db_column_int(&q, 1); szMax = db_column_int(&q, 2); db_finalize(&q); bigSizeName(sizeof(zBuf), zBuf, t); @ %d(szAvg) bytes average, %d(szMax) bytes max, %s(zBuf) total @
Compression Ratio: if( t/fsize < 5 ){ b = 10; fsize /= 10; }else{ b = 1; } a = t/fsize; @ %d(a):%d(b) @
Number Of Check-ins: n = db_int(0, "SELECT count(*) FROM event WHERE type='ci' /*scan*/"); @ %d(n) @
Number Of Files: n = db_int(0, "SELECT count(*) FROM filename /*scan*/"); @ %d(n) @
Number Of Wiki Pages: n = db_int(0, "SELECT count(*) FROM tag /*scan*/" " WHERE +tagname GLOB 'wiki-*'"); @ %d(n) @
Number Of Tickets: n = db_int(0, "SELECT count(*) FROM tag /*scan*/" " WHERE +tagname GLOB 'tkt-*'"); @ %d(n) @
Duration Of Project: n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)" " + 0.99"); @ %d(n) days or approximately %.2f(n/365.2425) years. @
Project ID:%h(db_get("project-code",""))
Fossil Version: @ %h(MANIFEST_DATE) %h(MANIFEST_VERSION) @ (%h(RELEASE_VERSION)) [compiled using %h(COMPILER_NAME)] @
SQLite Version:%.19s(sqlite3_sourceid()) @ [%.10s(&sqlite3_sourceid()[20])] (%s(sqlite3_libversion()))
Repository Rebuilt: @ %h(db_get_mtime("rebuilt","%Y-%m-%d %H:%M:%S","Never")) @ By Fossil %h(db_get("rebuilt","Unknown"))
Database Stats: zDb = db_name("repository"); @ %d(db_int(0, "PRAGMA %s.page_count", zDb)) pages, @ %d(db_int(0, "PRAGMA %s.page_size", zDb)) bytes/page, @ %d(db_int(0, "PRAGMA %s.freelist_count", zDb)) free pages, @ %s(db_text(0, "PRAGMA %s.encoding", zDb)), @ %s(db_text(0, "PRAGMA %s.journal_mode", zDb)) mode @
style_footer(); } /* ** COMMAND: dbstat* ** ** Usage: %fossil dbstat ?-brief | -b? ** ** Shows statistics and global information about the repository. ** ** The (-brief|-b) option removes any "long-running" statistics, namely ** those whose calculations are known to slow down as the repository ** grows. ** */ void dbstat_cmd(void){ i64 t, fsize; int n, m; int szMax, szAvg; const char *zDb; int brief; char zBuf[100]; const int colWidth = -19 /* printf alignment/width for left column */; brief = find_option("brief", "b",0)!=0; db_find_and_open_repository(0,0); fsize = file_size(g.zRepositoryName); bigSizeName(sizeof(zBuf), zBuf, fsize); fossil_print( "%*s%s\n", colWidth, "repository-size:", zBuf ); if( !brief ){ n = db_int(0, "SELECT count(*) FROM blob"); m = db_int(0, "SELECT count(*) FROM delta"); fossil_print("%*s%d (stored as %d full text and %d delta blobs)\n", colWidth, "artifact-count:", n, n-m, m); if( n>0 ){ int a, b; Stmt q; db_prepare(&q, "SELECT total(size), avg(size), max(size)" " FROM blob WHERE size>0"); db_step(&q); t = db_column_int64(&q, 0); szAvg = db_column_int(&q, 1); szMax = db_column_int(&q, 2); db_finalize(&q); bigSizeName(sizeof(zBuf), zBuf, t); fossil_print( "%*s%d average, " "%d max, %s total\n", colWidth, "artifact-sizes:", szAvg, szMax, zBuf); if( t/fsize < 5 ){ b = 10; fsize /= 10; }else{ b = 1; } a = t/fsize; fossil_print("%*s%d:%d\n", colWidth, "compression-ratio:", a, b); } n = db_int(0, "SELECT COUNT(*) FROM event e WHERE e.type='ci'"); fossil_print("%*s%d\n", colWidth, "checkins:", n); n = db_int(0, "SELECT count(*) FROM filename /*scan*/"); fossil_print("%*s%d across all branches\n", colWidth, "files:", n); n = db_int(0, "SELECT count(*) FROM tag /*scan*/" " WHERE tagname GLOB 'wiki-*'"); m = db_int(0, "SELECT COUNT(*) FROM event WHERE type='w'"); fossil_print("%*s%d (%d changes)\n", colWidth, "wikipages:", n, m); n = db_int(0, "SELECT count(*) FROM tag /*scan*/" " WHERE tagname GLOB 'tkt-*'"); m = db_int(0, "SELECT COUNT(*) FROM event WHERE type='t'"); fossil_print("%*s%d (%d changes)\n", colWidth, "tickets:", n, m); n = db_int(0, "SELECT COUNT(*) FROM event WHERE type='e'"); fossil_print("%*s%d\n", colWidth, "events:", n); n = db_int(0, "SELECT COUNT(*) FROM event WHERE type='g'"); fossil_print("%*s%d\n", colWidth, "tagchanges:", n); } n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)" " + 0.99"); fossil_print("%*s%d days or approximately %.2f years.\n", colWidth, "project-age:", n, n/365.2425); fossil_print("%*s%s\n", colWidth, "project-id:", db_get("project-code","")); fossil_print("%*s%s %s [%s] (%s)\n", colWidth, "fossil-version:", MANIFEST_DATE, MANIFEST_VERSION, RELEASE_VERSION, COMPILER_NAME); fossil_print("%*s%.19s [%.10s] (%s)\n", colWidth, "sqlite-version:", sqlite3_sourceid(), &sqlite3_sourceid()[20], sqlite3_libversion()); zDb = db_name("repository"); fossil_print("%*s%d pages, %d bytes/pg, %d free pages, " "%s, %s mode\n", colWidth, "database-stats:", db_int(0, "PRAGMA %s.page_count", zDb), db_int(0, "PRAGMA %s.page_size", zDb), db_int(0, "PRAGMA %s.freelist_count", zDb), db_text(0, "PRAGMA %s.encoding", zDb), db_text(0, "PRAGMA %s.journal_mode", zDb)); } /* ** WEBPAGE: urllist ** ** Show ways in which this repository has been accessed */ void urllist_page(void){ Stmt q; int cnt; login_check_credentials(); if( !g.perm.Admin ){ login_needed(); return; } style_header("URLs and Checkouts"); style_submenu_element("Stat", "Repository Stats", "stat"); style_submenu_element("Schema", "Repository Schema", "repo_schema"); @
URLs
@ db_prepare(&q, "SELECT substr(name,9), datetime(mtime,'unixepoch')" " FROM config WHERE name GLOB 'baseurl:*' ORDER BY 2 DESC"); cnt = 0; while( db_step(&q)==SQLITE_ROW ){ @ @ cnt++; } db_finalize(&q); if( cnt==0 ){ @ } @
%h(db_column_text(&q,0))%h(db_column_text(&q,1))
(none)
@
Checkouts
@ db_prepare(&q, "SELECT substr(name,7), datetime(mtime,'unixepoch')" " FROM config WHERE name GLOB 'ckout:*' ORDER BY 2 DESC"); cnt = 0; while( db_step(&q)==SQLITE_ROW ){ @ @ cnt++; } db_finalize(&q); if( cnt==0 ){ @ } @
%h(db_column_text(&q,0))%h(db_column_text(&q,1))
(none)
style_footer(); } /* ** WEBPAGE: repo_schema ** ** Show the repository schema */ void repo_schema_page(void){ Stmt q; login_check_credentials(); if( !g.perm.Admin ){ login_needed(); return; } style_header("Repository Schema"); style_submenu_element("Stat", "Repository Stats", "stat"); style_submenu_element("URLs", "URLs and Checkouts", "urllist"); db_prepare(&q, "SELECT sql FROM %s.sqlite_master WHERE sql IS NOT NULL", db_name("repository")); @
  while( db_step(&q)==SQLITE_ROW ){
    @ %h(db_column_text(&q, 0));
  }
  @ 
db_finalize(&q); style_footer(); }