-
Notifications
You must be signed in to change notification settings - Fork 1
/
transaction.h
104 lines (94 loc) · 2.5 KB
/
transaction.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#ifdef OPEN_TRANSACTION
#include "list.h"
#include "types.h"
#ifndef TRANSACTION_H
#define TRANSACTION_H
typedef struct
{
cursor_t cursor;
statement_type_t statement_type;
row_t row_value;
list_node_t entry;
} transaction_t;
typedef transaction_t trans_t;
// a dummy list node
trans_t *trans = NULL;
// this function will run before main
void __attribute__((constructor)) init_transaction()
{
trans = (trans_t *)malloc(sizeof(trans_t));
init_list_head(&(trans->entry));
}
void __attribute__((destructor)) free_transaction()
{
list_node_t *pos, *next;
list_for_each_safe(pos, next, &(trans->entry))
{
if (pos != NULL)
{
list_del(pos);
free(list_entry(pos, trans_t, entry));
}
}
if (trans != NULL)
free(trans);
}
void transaction_push(cursor_t *cursor, row_t *row, statement_type_t type)
{
trans_t *node = (trans_t *)malloc(sizeof(trans_t));
memcpy((void *)&(node->cursor), (const void *)cursor, sizeof(cursor_t));
memcpy((void *)&(node->row_value), (const void *)row, sizeof(row_t));
node->statement_type = type;
list_add_tail(&(node->entry), &(trans->entry));
}
trans_t *transaction_pop()
{
if (list_empty(&(trans->entry)))
return NULL;
list_node_t *last = (trans->entry).prev;
list_del(last);
return list_entry(last, trans_t, entry);
}
void transaction_commit()
{
// TODO: 有可能是写同一页的, 需要优化一下
// 在 pager_t 中加入 dirty page 标记
list_node_t *pos, *next;
list_for_each_safe(pos, next, &(trans->entry))
{
assert(pos != NULL);
trans_t *node = list_entry(pos, trans_t, entry);
cursor_t *cursor = &(node->cursor);
pager_t *pager = cursor->table->pager;
assert(cursor->page_num < pager->num_pages);
pager_flush(pager, cursor->page_num);
fsync(pager->file_descriptor);
list_del(pos), free(node);
}
}
// rollback only one step
void transaction_rollback()
{
trans_t *last = transaction_pop();
if (last == NULL)
return;
cursor_t *cursor = &(last->cursor);
row_t *row = &(last->row_value);
switch (last->statement_type)
{
case STATEMENT_INSERT:
leaf_node_fake_delete(cursor, row->id);
break;
case STATEMENT_DELETE:
leaf_node_insert(cursor, row->id, row);
break;
case STATEMENT_UPDATE:
serialize_row(row, cursor_value(cursor));
break;
default:
assert(0);
}
free(last);
}
#endif
#endif