-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtable.h
More file actions
181 lines (147 loc) · 5.76 KB
/
table.h
File metadata and controls
181 lines (147 loc) · 5.76 KB
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#pragma once
#define SEGMENTS_HASH(ss) MurmurHash2((char *)(ss) + sizeof(struct segments), (ss)->size_used, MURMURHASH_SEED)
#define T_RDLOCK 1 << 0
#define T_WRLOCK 1 << 1
#define TAB_CREATE 1 << 0
struct segment
{
date_t date; /* 32 */
segment_size_t size; /* 32 */
segment_no_t segment; /* 16 */
/* dynamically sized; to find next segment, do:
* sizeof(struct segment) + msgid_len
*/
msgid_len_t msgid_len; /* 8 */
msgid_t msgid[];
} __attribute__ ((packed));
/* when we see a new file, allocate 4k for it. This struct goes at the start
* of that 4k, and the rest is multiple dynamically sized struct segment.
* When we fill up 4k, get a new block and put a reference in next_segments */
struct segments
{
uint32_t hash; /* 32;CRC check for segments[] */
page_off_t next_segments; /* 32;offset to next page of segments */
segment_magic_t magic; /* 8;magic byte, always 0x4e 'N' */
segment_count_t segment_count; /* 8;how many segments in this page */
fileid_size_t size_used; /* 16;bytes used by segments[] */
fileid_t fileid; /* 32;fileid */
struct segment segments[];
} __attribute__ ((packed));
struct fileid
{
fileid_t fileid; /* 32 */
fileid_magic_t magic; /* 16;magic bytes; AZ */
fileid_page_t page_alloc; /* 8;pages allocated for file */
uint8_t reserved1; /* 8;padding */
/* offset [in pages] to first page of segments for this fileid */
page_off_t first_segments; /* 32 */
page_off_t cur_segments; /* 32 */
} __attribute__ ((packed));
/* header that goes at the start of every .fdat file */
#define FDAT_HEADER_CURRENT_VERSION 1
struct fdat_header
{
file_magic_t file_magic; /* 64 */
file_version_t file_version; /* 16 */
uint16_t reserved1; /* 16 .. add something to align */
fileid_t fileid_min; /* 32 */
fileid_t fileid_max; /* 32 */
fileid_t fileid_min_req; /* 32 */
fileid_t fileid_max_req; /* 32 */
page_off_t files_used; /* 32 */
page_off_t files_allocated; /* 32 */
} __attribute__ ((packed));
/* header that goes at the start of every .sdat file */
#define SDAT_HEADER_CURRENT_VERSION 1
/* unused flags: 0x02 0x04 0x08 0x10 0x20 0x40 0x80 */
#define SDAT_FLAGS_DIRTY 0x01 /* we've written to this file */
struct sdat_header
{
file_magic_t file_magic; /* 64 */
file_version_t file_version; /* 16 */
file_flags_t flags; /* 8 */
int8_t reserved1; /* 8 bits of alignment */
page_off_t first_segment; /* 32; not really used.. */
page_off_t next_free_segment; /* 32 */
page_off_t segments_allocated; /* 32 */
} __attribute__ ((packed));
/* a neat tidy place to keep everything associated with a dat file */
struct dat_file
{
fd_t fd;
mmap_t m;
union
{
struct fdat_header *fh;
struct sdat_header *sh;
};
#if USE_M_LOCK
// mmap lock, for either per-fileid or per-segments lock
uint32_t *m_lock;
#endif
union
{
struct fileid *files;
//struct segments *segments; // not needed yet
};
};
/* one of these represents an open table */
struct dat_files
{
char *basename;
struct dat_file f, s;
/* table lock - if contention gets bad, we'll rethink this */
pthread_rwlock_t t_lock;
uint64_t last_access; /* for closing LRU */
uint8_t opened;
};
struct tables
{
pthread_mutex_t L_open_tables;
table_count_t open_tables;
table_count_t dats_allocated;
struct dat_files *dats; /* array of open dats */
};
/* for returning arbitrary errors from functions that need to return a
* pointer. Just compare the returned value to sentinels.foo */
struct
{
/* get_first_segments_for_file / get_cur_segments_for_file */
struct segments segment_page_out_of_bounds;
} sentinels;
ssize_t filesize(fd_t);
uint32_t MurmurHash2(const void *, uint32_t, uint32_t);
uint64_t calc_file_offset(struct dat_files *, struct fileid *);
uint64_t calc_segments_offset(struct dat_files *, struct segments *);
inline struct fileid *get_files_offset(struct dat_file *);
inline struct segments *get_segments_offset(struct dat_file *);
inline struct segments *get_first_segments_for_file(struct dat_files *, struct fileid *);
inline struct segments *get_cur_segments_for_file(struct dat_files *, struct fileid *);
inline struct segments *get_next_segments(mmap_t, struct segments *);
inline struct segment *get_next_segment(struct segment *);
struct fileid *add_fileid(struct dat_file *, const fileid_t);
int32_t table_lock_init(struct dat_files *);
int32_t table_lock_free(struct dat_files *);
int32_t table_lock(struct dat_files *, int8_t);
int32_t table_unlock(struct dat_files *);
int32_t tables_sync(void);
int32_t resize_mmaped_file(uint64_t, struct dat_file *);
int32_t fdat_resize(uint64_t, struct dat_file *);
int32_t sdat_resize(uint64_t, struct dat_file *);
int32_t table_nuke_segments_page(struct dat_files *, struct segments *);
int32_t table_recover_segments_page(struct dat_files *, struct segments *);
int32_t table_repair_rebuild_fileid(struct dat_files *, struct fileid *, fileid_t);
int32_t table_backup(struct dat_files *);
int32_t table_check(struct dat_files *);
int32_t table_close_no_t_lock(struct dat_files *);
int32_t table_close(struct dat_files *);
int32_t tables_close_all(void);
int32_t tables_close_lru(void);
int32_t table_open_existing_fdat(struct dat_files *);
int32_t table_open_existing_sdat(struct dat_files *);
int32_t table_open_existing(struct dat_files *, fileid_t, fileid_t);
int32_t table_create(uint64_t, struct dat_files *, fileid_t, fileid_t);
uint32_t get_pos_for_fileid(const fileid_t);
struct dat_files *get_table_for_fileid(const fileid_t, int8_t);
struct segment *find_segment(struct segment_local *);
int32_t add_segment(struct segment_local *);