doctor.v

2.3 KB · raw

1//! Repository structure and storage measurements used by Doctor.2module storage34/// Storage counts and structural findings from one database snapshot.5pub struct DoctorStats {6pub mut:7	objects      i648	saves        i649	checkpoints  i6410	cached_files i6411	file_entries i6412	object_bytes i6413	packed_bytes i6414	unused       i6415	pending      []string16	state        map[string]string17	problems     []string18}1920/// Inspect references, scalar storage invariants and machine-local state.21pub fn (s &Store) doctor_stats() !DoctorStats {22	mut out := DoctorStats{}23	mut sizes := s.db.prepare('SELECT COUNT(*), COALESCE(SUM(size), 0),24		COALESCE(SUM(length(data)), 0) FROM objects')!25	defer { sizes.finalize() }26	if sizes.step()! {27		out.objects = sizes.int(0)28		out.object_bytes = sizes.int(1)29		out.packed_bytes = sizes.int(2)30	}31	mut counts := s.db.prepare('SELECT32		(SELECT COUNT(*) FROM saves),33		(SELECT COUNT(*) FROM saves WHERE is_checkpoint = 1),34		(SELECT COUNT(*) FROM file_cache),35		(SELECT COUNT(*) FROM save_files),36		(SELECT COUNT(*) FROM objects WHERE hash NOT IN (SELECT hash FROM save_files))')!37	defer { counts.finalize() }38	if counts.step()! {39		out.saves = counts.int(0)40		out.checkpoints = counts.int(1)41		out.cached_files = counts.int(2)42		out.file_entries = counts.int(3)43		out.unused = counts.int(4)44	}45	mut foreign := s.db.prepare('PRAGMA foreign_key_check')!46	defer { foreign.finalize() }47	for foreign.step()! {48		out.problems << 'broken reference in ${foreign.text(0)} row ${foreign.int(1)} to ${foreign.text(2)}'49	}50	mut invalid := s.db.prepare("SELECT save_id, path FROM save_files51		WHERE executable NOT IN (0, 1)52		OR typeof(executable) != 'integer'53		UNION ALL54		SELECT id, 'invalid save metadata' FROM saves55		WHERE is_checkpoint NOT IN (0, 1)56		OR typeof(is_checkpoint) != 'integer'57		OR id = ''58		OR typeof(created_at) != 'integer'59		OR created_at < 060		OR typeof(size_bytes) != 'integer'61		OR size_bytes < 0")!62	defer { invalid.finalize() }63	for invalid.step()! {64		out.problems << 'invalid metadata in save ${invalid.text(0)}: ${invalid.text(1)}'65	}66	mut state := s.db.prepare('SELECT key, value FROM state')!67	defer { state.finalize() }68	for state.step()! {69		key := state.text(0)70		out.state[key] = state.text(1)71		if key.starts_with('strip_pending:') {72			out.pending << key.all_after('strip_pending:')73		}74	}75	out.pending.sort()76	return out77}