Skip to content

Commit 1f932d8

Browse files
author
Julien Sagot
committed
Added geneweb-compact tool
1 parent 9de5318 commit 1f932d8

6 files changed

Lines changed: 208 additions & 0 deletions

File tree

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
EXE = \
55
check_base/check_base.exe \
6+
compact/compact.exe \
67
dag2html/main.exe \
78
gwFix/gwFixBase.exe \
89
gwFix/gwFixBurial.exe \

compact/README.MD

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# geneweb-compact
2+
3+
A tool to remove unused values from your database.
4+
5+
It only support old legacy gwbd format.
6+
7+
## Why?
8+
9+
When modifiying a text, deleting a person or a family, GeneWeb does
10+
not actually delete data, it just remove the links to this data,
11+
instead.
12+
13+
It can be a security problem, if you though you erased sensitive data
14+
from a note which is still present in the database.
15+
16+
Also, as the time goes by, leftover data can grow waste some space en
17+
resources.
18+
19+
## What?
20+
21+
Current stage of the tool only report and dump leftover data. Next
22+
step is to actually perfom a database cleanup.

compact/compact.ml

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
open Geneweb
2+
open Def
3+
open Dbdisk
4+
5+
let fast = ref true
6+
let step_strings = ref false
7+
let step_persons = ref false
8+
let step_families = ref false
9+
10+
let load_array a = if !fast then a.load_array ()
11+
let clear_array a = a.clear_array ()
12+
13+
let split_sname base i = Mutil.split_sname @@ base.data.strings.get i
14+
let split_fname base i = Mutil.split_fname @@ base.data.strings.get i
15+
16+
let scan base string person family =
17+
let mark t i = try t.(i) <- true with _ -> failwith @@ string_of_int i in
18+
if !step_strings then begin
19+
load_array base.data.strings ;
20+
let rev = Hashtbl.create base.data.strings.len in
21+
for i = 0 to base.data.strings.len - 1 do
22+
Hashtbl.add rev (base.data.strings.get i) i
23+
done ;
24+
let opt_mark t s = match Hashtbl.find_opt rev s with Some x -> mark t x | None -> () in
25+
let t = Array.make base.data.strings.len false in
26+
load_array base.data.persons ;
27+
for i = 0 to base.data.persons.len - 1 do
28+
let p = base.data.persons.get i in
29+
mark t p.first_name ;
30+
List.iter (opt_mark t) (split_fname base p.first_name) ;
31+
mark t p.surname ;
32+
List.iter (opt_mark t) (split_sname base p.surname) ;
33+
opt_mark t @@ Name.concat (base.data.strings.get p.first_name) (base.data.strings.get p.surname) ;
34+
mark t p.image ;
35+
mark t p.public_name ;
36+
List.iter (mark t) p.qualifiers ;
37+
List.iter (mark t) p.aliases ;
38+
List.iter (mark t) p.first_names_aliases ;
39+
List.iter (mark t) p.surnames_aliases ;
40+
List.iter begin fun {t_name;t_ident;t_place; _ } ->
41+
mark t t_ident ;
42+
mark t t_place ;
43+
(match t_name with Tname i -> mark t i | _ -> ()) ;
44+
end p.titles ;
45+
mark t p.occupation ;
46+
mark t p.birth_place ;
47+
mark t p.birth_note ;
48+
mark t p.birth_src ;
49+
mark t p.baptism_place ;
50+
mark t p.baptism_note ;
51+
mark t p.baptism_src ;
52+
mark t p.death_place ;
53+
mark t p.death_note ;
54+
mark t p.death_src ;
55+
mark t p.burial_place ;
56+
mark t p.burial_note ;
57+
mark t p.burial_src ;
58+
mark t p.notes ;
59+
mark t p.psources ;
60+
List.iter (fun {r_sources;_} -> mark t r_sources) p.rparents ;
61+
List.iter begin fun {epers_name;epers_place;epers_reason;epers_note;epers_src;_} ->
62+
(match epers_name with Epers_Name i -> mark t i | _ -> ()) ;
63+
mark t epers_place ;
64+
mark t epers_reason ;
65+
mark t epers_note ;
66+
mark t epers_src ;
67+
end p.pevents
68+
done ;
69+
clear_array base.data.persons ;
70+
load_array base.data.families ;
71+
for i = 0 to base.data.families.len - 1 do
72+
let f = base.data.families.get i in
73+
mark t f.marriage_place ;
74+
mark t f.marriage_note ;
75+
mark t f.marriage_src ;
76+
mark t f.comment ;
77+
mark t f.origin_file ;
78+
mark t f.fsources ;
79+
List.iter begin fun {efam_name;efam_place;efam_reason;efam_note;efam_src;_} ->
80+
(match efam_name with Efam_Name i -> mark t i | _ -> ()) ;
81+
mark t efam_place ;
82+
mark t efam_reason ;
83+
mark t efam_note ;
84+
mark t efam_src ;
85+
end f.fevents
86+
done ;
87+
clear_array base.data.families ;
88+
clear_array base.data.strings ;
89+
string base t
90+
end ;
91+
if !step_persons then begin
92+
load_array base.data.persons ;
93+
let t = Array.make base.data.persons.len false in
94+
for i = 0 to base.data.persons.len - 1 do
95+
if (base.data.persons.get i).key_index <> Gwdb1.dummy_iper then mark t i
96+
done ;
97+
clear_array base.data.persons ;
98+
person base t
99+
end ;
100+
if !step_families then begin
101+
load_array base.data.families ;
102+
let t = Array.make base.data.families.len false in
103+
for i = 0 to base.data.families.len - 1 do
104+
if (base.data.families.get i).fam_index <> Gwdb1.dummy_ifam then mark t i
105+
done ;
106+
clear_array base.data.families ;
107+
family base t
108+
end
109+
110+
let report base =
111+
let aux fn _base t =
112+
let cnt = ref 0 in
113+
for i = 0 to Array.length t - 1 do if not t.(i) then incr cnt done ;
114+
fn !cnt
115+
in
116+
scan
117+
base
118+
(aux @@ fun c -> Printf.printf "Number of unused strings: %d\n" c)
119+
(aux @@ fun c -> Printf.printf "Number of ghost persons: %d\n" c)
120+
(aux @@ fun c -> Printf.printf "Number of ghost families: %d\n" c)
121+
122+
let dump base =
123+
let dump_istr base t =
124+
for i = 0 to Array.length t - 1 do
125+
if not t.(i) then begin
126+
Printf.printf "=== [START ISTR %d] ===\n%s\n=== [END ISTR %d] ===\n\n" i (base.data.strings.get i) i
127+
end
128+
done
129+
in
130+
let dump_iper _base t =
131+
for i = 0 to Array.length t - 1 do
132+
if not t.(i) then begin Printf.printf "Ghost person: %d\n" i end
133+
done
134+
in
135+
let dump_ifam _base t =
136+
for i = 0 to Array.length t - 1 do
137+
if not t.(i) then begin Printf.printf "Ghost family: %d\n" i end
138+
done
139+
in
140+
scan base dump_istr dump_iper dump_ifam
141+
142+
let steps = ref "strings,persons,families"
143+
let bname = ref ""
144+
let action = ref None
145+
let usage = "Usage: " ^ Sys.argv.(0) ^ " [OPTION] ACTIOn base"
146+
147+
let speclist =
148+
[ ( "-mem"
149+
, Arg.Clear fast
150+
, " slower, but use less memory" )
151+
; ( "-step"
152+
, Arg.Set_string steps
153+
, " STEPS steps to perform. Default is " ^ !steps )
154+
; ( "-report"
155+
, Arg.Unit (fun () -> action := Some `report)
156+
, " only report number of unused values" )
157+
; ( "-dump"
158+
, Arg.Unit (fun () -> action := Some `dump)
159+
, " dump unuse values" )
160+
]
161+
162+
let _ =
163+
Arg.parse speclist (fun s -> bname := s) usage ;
164+
Secure.set_base_dir (Filename.dirname !bname) ;
165+
if !bname = "" then begin Arg.usage speclist usage ; exit 2 end;
166+
List.iter begin function
167+
| "strings" -> step_strings := true
168+
| "persons" -> step_persons := true
169+
| "families" -> step_families := true
170+
| _ -> Arg.usage speclist usage ; exit 2
171+
end (String.split_on_char ',' !steps) ;
172+
Lock.control (Mutil.lock_file !bname) false ~onerror:Lock.print_try_again @@ fun () ->
173+
let base = Gwdb1.OfGwdb.base (Gwdb.open_base !bname) in
174+
match !action with
175+
| None -> Arg.usage speclist usage ; exit 2
176+
| Some `dump -> dump base
177+
| Some `report -> report base

compact/dune

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
(executable
2+
(name compact)
3+
(public_name geneweb-compact)
4+
(libraries unix str geneweb.gwdb1 geneweb.wserver geneweb)
5+
(modules compact)
6+
)

compact/dune-project

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
(lang dune 1.10)
2+
(name geneweb-compact)

compact/geneweb-compact.opam

Whitespace-only changes.

0 commit comments

Comments
 (0)