Skip to content

Commit 6a23a86

Browse files
authored
Merge pull request #7 from bglid/feature/min-disk-persistence
Feature/min disk persistence
2 parents a2b6c52 + 4da6f20 commit 6a23a86

24 files changed

Lines changed: 437 additions & 111 deletions

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,6 @@ setup.log
3434

3535
# Local OPAM switch
3636
_opam/
37+
38+
# db file
39+
*.db

bin/main.ml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
11
let () =
22
Printf.printf "*********SQCaml*********\n\r";
3-
SQCaml.Repl.start ()
3+
let db_dir =
4+
if Array.length Sys.argv >= 2 then
5+
Sys.argv.(1)
6+
else
7+
"sqcaml.db"
8+
in
9+
let db = SQCaml.Db_session.open_db db_dir in
10+
try SQCaml.Repl.start db
11+
with exn ->
12+
SQCaml.Db_session.close_db db;
13+
raise exn

lib/ast/ast.ml

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,6 @@ type binop_t =
1212
| Comp
1313
[@@deriving show]
1414

15-
(* type column_types = *)
16-
(* | Int_col *)
17-
(* | Float_col *)
18-
(* | String_col *)
19-
(* | Bool_col *)
20-
(* [@@deriving show] *)
21-
2215
(** Our Abstract Syntax Tree for interpreter, hooray! *)
2316
type expr =
2417
| Int of int
@@ -48,10 +41,9 @@ type statement =
4841
type meta_command =
4942
| Help
5043
| Exit
44+
| Tree
5145
| Unk_mcmd of string
52-
[@@deriving show]
5346

5447
type top_level =
5548
| Statement of statement
5649
| Meta_command of meta_command
57-
[@@deriving show]

lib/ast/insert.ml

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,49 @@
11
(* abstraction to make a module for preparing and executing insert statement*)
22

33
type t = {
4-
table : Table.t;
4+
(* tree : Btree.t; *)
55
fields : string list;
66
values : Constant.t list;
77
}
88
[@@deriving show]
99

1010
(* HACKY for now, new table each time *)
11-
let make (tablename : string) (fields : string list) (values : Constant.t list)
12-
: t =
13-
{ table = Table.create_table ~id:777 ~table_name:tablename; fields; values }
11+
(* let make (tablename : string) (fields : string list) (values : Constant.t list) *)
12+
let make (fields : string list) (values : Constant.t list) : t =
13+
(* { table = Table.create_table ~id:777 ~table_name:tablename; fields; values } *)
14+
{ fields; values }
1415

15-
let execute_insert (preped_insert : t) : string =
16-
(* let new_table = Table.add_row ~table:temp_table ~row:new_row in *)
17-
let new_fields =
18-
List.fold_left
19-
(fun acc l ->
20-
match l with
21-
| Constant.ConstStr s -> acc ^ " " ^ s
22-
| Constant.ConstInt d -> acc ^ " " ^ Int.to_string (Int32.to_int d))
23-
"" preped_insert.values
16+
let execute_insert (db : Db_session.t) (preped_insert : t) : string =
17+
(* serialize the insert to a page*)
18+
let new_row =
19+
match preped_insert.values with
20+
| [ id; stop; rail ] ->
21+
Table.make_row
22+
~id:(Int32.to_int (Constant.to_int id))
23+
~stop_name:(Constant.to_str stop) ~rail_line:(Constant.to_str rail)
24+
| _ -> failwith "Wrong amount of args passed"
2425
in
25-
(* new_fields *)
26-
"Inserted" ^ new_fields ^ " into " ^ preped_insert.table.table_name
26+
let cursor = Cursor.tree_end db.index in
2727

28-
(* Printf.printf "Inserted %d %s %s into Table %d" id stop_name rail_name *)
29-
(* preped_insert.table.table_name *)
28+
(* check to guard capacity*)
29+
let leaf = Btree.get_node db.index cursor.page_num in
30+
if leaf.cur_size >= leaf.capacity then
31+
failwith "HELP! please implement splitting plz."
32+
else
33+
(* serialize the page and write to a block! *)
34+
let page =
35+
Table.serialize_to_page new_row
36+
~block_size:(File_manager.get_blocksize db.file_manager)
37+
in
38+
let row_block =
39+
Storage_manager.append ~storage_m:db.storage_manager ~page
40+
in
41+
(* block num where we want to write to disk!!*)
42+
let row_block_num = Page.Block.block_num row_block in
43+
let key = Keys.Integer (Int32.of_int new_row.id) in
44+
(* getting and writing our tree node to disk FINALLY*)
45+
Cursor.leaf_node_insert cursor key row_block_num;
46+
47+
(* printing the res *)
48+
let res = "Inserted " ^ new_row.stop_name ^ " " ^ new_row.rail_line ^ " " in
49+
res

lib/ast/select.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ type t = {
1010
let make (fields : string list) (tablename : string) : t =
1111
{ table = Table.create_table ~id:777 ~table_name:tablename; fields }
1212

13-
let execute_select (preped_select : t) : string =
13+
let execute_select (_ : Db_session.t) (preped_select : t) : string =
1414
let selected_fields =
1515
List.fold_left
1616
(fun acc l ->
1717
match l with
18-
| "id" -> acc ^ " 1"
18+
(* | "id" -> acc ^ " 1" *)
1919
| "stop_name" -> acc ^ "englewood"
2020
| "rail_line" -> acc ^ " G"
2121
| _ -> "not a valid field in the table")

lib/ast/table.ml

Lines changed: 69 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,41 +15,86 @@ type t = {
1515
}
1616
[@@deriving show]
1717

18+
(* hard coding rows for serialization *)
19+
let stop_name_size = 64
20+
let rail_line_size = 64
21+
let id_offset = 0
22+
let stop_offset = id_offset + 4
23+
let rail_offset = stop_name_size + stop_offset
24+
let row_size = 4 + stop_name_size + rail_line_size
1825
let make_row ~id ~stop_name ~rail_line : row_t = { id; stop_name; rail_line }
1926

2027
let create_table ~(id : int) ~(table_name : string) : t =
21-
{ table_id = id; table_name; table_fields = []; rows = [] }
28+
let rows = [] in
29+
{ table_id = id; table_name; table_fields = []; rows }
2230

2331
(* let open_table ~(table_name : string) : t = *)
2432
(* match table_name with *)
2533
(* | *)
2634

27-
let already_in_table ~(table : t) ~(row : row_t) : bool =
28-
(* List.mem row table.rows *)
29-
let rec search (table_rows : row_t list) (id : int) : bool =
30-
match table_rows with
31-
| [] -> false
32-
| h :: tail ->
33-
if h.id = id then
34-
true
35-
else
36-
search tail id
37-
in
38-
search table.rows row.id
35+
(* let already_in_table ~(table : t) ~(row : row_t) : bool = *)
36+
(* (* List.mem row table.rows *) *)
37+
(* let rec search (table_rows : row_t list) (id : int) : bool = *)
38+
(* match table_rows with *)
39+
(* | [] -> false *)
40+
(* | h :: tail -> *)
41+
(* if h.id = id then *)
42+
(* true *)
43+
(* else *)
44+
(* search tail id *)
45+
(* in *)
46+
(* search table.rows row.id *)
3947

4048
(* currently this is a bit functional in it's nature
4149
always returning a new table rather than adjusting the existing one.
4250
May want to consider changing rows to be mutable, or need to consider disk
4351
writes here - TBD *)
44-
let add_row ~(table : t) ~(row : row_t) : t =
45-
if already_in_table ~table ~row then
46-
table
52+
(* let add_row ~(table : t) ~(row : row_t) : t = *)
53+
(* if already_in_table ~table ~row then *)
54+
(* table *)
55+
(* else *)
56+
(* (* let new_row_list = List.fold_left (fun acc l -> acc :: l) table.rows [row] in *) *)
57+
(* let new_row_list = table.rows @ [ row ] in *)
58+
(* { *)
59+
(* table_id = table.table_id; *)
60+
(* table_name = table.table_name; *)
61+
(* table_fields = table.table_fields; *)
62+
(* rows = new_row_list; *)
63+
(* num_rows = List.length new_row_list; *)
64+
(* } *)
65+
66+
let pad_fixed_size (size : int) (s : string) : string =
67+
if String.length s > size then
68+
failwith
69+
(Printf.sprintf "String too long.\nGreater than input size of %d" size)
4770
else
48-
(* let new_row_list = List.fold_left (fun acc l -> acc :: l) table.rows [row] in *)
49-
let new_row_list = table.rows @ [ row ] in
50-
{
51-
table_id = table.table_id;
52-
table_name = table.table_name;
53-
table_fields = table.table_fields;
54-
rows = new_row_list;
55-
}
71+
s ^ String.make (size - String.length s) '\000'
72+
73+
let trim_null (s : string) : string =
74+
match String.index_opt s '\000' with
75+
| None -> s
76+
| Some thing -> String.sub s 0 thing
77+
78+
let serialize_to_page (row : row_t) ~(block_size : int) : Page.Page.t =
79+
if row_size > block_size then
80+
failwith "Row doesn't fit into page";
81+
82+
let page = Page.Page.make ~block_size in
83+
(* serialize id, stop name, then rail name *)
84+
Page.Page.set_int32 page id_offset (Int32.of_int row.id);
85+
Page.Page.set_string_raw page stop_offset
86+
(pad_fixed_size stop_name_size row.stop_name);
87+
Page.Page.set_string_raw page rail_offset
88+
(pad_fixed_size rail_line_size row.rail_line);
89+
page
90+
91+
let deserialize_from_page (page : Page.Page.t) : row_t =
92+
(* get the id, stop name, and rail name from the Int32 offsets*)
93+
let id = Int32.to_int (Page.Page.get_int32 page id_offset) in
94+
let stop_name =
95+
trim_null (Page.Page.get_string_raw page stop_offset stop_name_size)
96+
in
97+
let rail_line =
98+
trim_null (Page.Page.get_string_raw page rail_offset rail_line_size)
99+
in
100+
{ id; stop_name; rail_line }

lib/btree/btree.ml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,3 +120,60 @@ let get_node (btree : t) (p : int) : Nodes.t =
120120
Storage_manager.get_block ~storage_m:btree.storage_m ~block_num:p
121121
in
122122
deserialize page btree.key block_size
123+
124+
[@@@warning "-32"]
125+
126+
let empty_node (btree : t) : Nodes.t =
127+
let block_size = File_manager.get_blocksize btree.storage_m.file_manager in
128+
let key_type = btree.key in
129+
let capacity = get_num_keys block_size key_type in
130+
{
131+
Nodes.node_t = Leaf;
132+
Nodes.parent = 0;
133+
Nodes.cur_size = 0;
134+
Nodes.keys = Array.init capacity (fun _ -> Keys.empty_key key_type);
135+
Nodes.pointers = Array.init (capacity + 1) (fun _ -> unused_pointer_serial);
136+
Nodes.capacity;
137+
Nodes.key_type;
138+
}
139+
140+
(* Make an empty btree initialized to disk *)
141+
let create (storage_m : Storage_manager.t) (key_type : Keys.t) : t =
142+
let block_size = File_manager.get_blocksize storage_m.file_manager in
143+
let meta = Storage_manager.get_head_page ~storage_manager:storage_m in
144+
Page.Page.set_int32 meta 4 (Int32.of_int 1);
145+
Storage_manager.update_block_num ~storage_m ~block_num:0 ~page:meta;
146+
let capacity = get_num_keys block_size key_type in
147+
let root_node =
148+
{
149+
Nodes.node_t = Leaf;
150+
Nodes.parent = 0;
151+
Nodes.cur_size = 0;
152+
Nodes.keys = Array.init capacity (fun _ -> Keys.empty_key key_type);
153+
Nodes.pointers =
154+
Array.init (capacity + 1) (fun _ -> unused_pointer_serial);
155+
Nodes.capacity;
156+
Nodes.key_type;
157+
}
158+
in
159+
let root_page = serialize root_node block_size in
160+
let _ = Storage_manager.append ~storage_m ~page:root_page in
161+
{ storage_m; key = key_type; root = root_node; root_num = 1 }
162+
163+
let open_btree (storage_m : Storage_manager.t) (key_type : Keys.t) : t =
164+
let block_size = File_manager.get_blocksize storage_m.file_manager in
165+
let meta = Storage_manager.get_head_page ~storage_manager:storage_m in
166+
let root_num = Int32.to_int (Page.Page.get_int32 meta 4) in
167+
if root_num = 0 then
168+
(* create btree instead *)
169+
create storage_m key_type
170+
else
171+
let root_page = Storage_manager.get_block ~storage_m ~block_num:root_num in
172+
let root_node = deserialize root_page key_type block_size in
173+
{ storage_m; key = key_type; root = root_node; root_num }
174+
175+
[@@@warning "-32"]
176+
177+
let print_tree (tree : t) : string =
178+
let root_node = get_node tree tree.root_num in
179+
Nodes.print_leaf_node root_node

lib/btree/btree.mli

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
type t
1+
type t = {
2+
storage_m : Storage_manager.t; (* file used to store to disk *)
3+
key : Keys.t;
4+
mutable root : Nodes.t;
5+
mutable root_num : int;
6+
}
27
(** Struct for the B+ Tree *)
38

49
val serialize : Nodes.t -> int -> Page.Page.t
@@ -22,3 +27,9 @@ val write_node_append : t -> Nodes.t -> int
2227
val get_node : t -> int -> Nodes.t
2328
(** Get a block from the btree [t] and deserializeit using the pointer [p] into
2429
a btree node *)
30+
31+
val open_btree : Storage_manager.t -> Keys.t -> t
32+
(** Opens btree given [storage manager] and [key type]. If it doesn't exist,
33+
creates a new btree *)
34+
35+
val print_tree : t -> string

lib/btree/nodes.ml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,16 @@ let int32_to_node_t (i32 : Int32.t) : node_type =
3636
else if i32 = internal_serial then
3737
Internal
3838
else
39-
failwith "WRONG i32!"
39+
failwith (Printf.sprintf "WRONG i32: %ld" i32)
40+
41+
let print_leaf_node (n : t) : string =
42+
if n.node_t <> Leaf then
43+
"Not a leaf node"
44+
else
45+
let lines =
46+
List.init n.cur_size (fun i ->
47+
match n.keys.(i) with
48+
| Keys.Integer n -> Printf.sprintf "- %d\n" (Int32.to_int n)
49+
| Keys.Varchar v -> Printf.sprintf "- %s\n" v)
50+
in
51+
Printf.sprintf "leaf (size %d)\n%s" n.cur_size (String.concat "" lines)

lib/btree/nodes.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ type t = {
1919

2020
val serialize_node : node_type -> Int32.t
2121
val int32_to_node_t : Int32.t -> node_type
22+
val print_leaf_node : t -> string

0 commit comments

Comments
 (0)