-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathn2diskdb.c
More file actions
405 lines (348 loc) · 11.3 KB
/
n2diskdb.c
File metadata and controls
405 lines (348 loc) · 11.3 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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
#include "n2diskdb.h"
#include "datatypes.h"
#include "iptypes.h"
#include "n2encoding.h"
#include <sys/time.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* ------------------------------------------------------------------------- *\
* FUNCTION diskdb_now (date, index) *
* --------------------------------- *
* Gathers the current time and turns it into an apropriate integer *
* representing the date (in the format YYYYMMDD) and an index of the *
* current minute (ranging from 0 to 1439 inclusive). *
\* ------------------------------------------------------------------------- */
void diskdb_now (unsigned int *tdate, int *tindex)
{
time_t ti;
struct tm tim;
ti = time (NULL);
localtime_r (&ti, &tim);
*tdate = (10000 * (tim.tm_year + 1900)) +
(100 * (tim.tm_mon+1)) + tim.tm_mday;
*tindex = (60 * (tim.tm_hour)) + tim.tm_min;
}
/* ------------------------------------------------------------------------- *\
* FUNCTION tdate_sub (date, amount) *
* --------------------------------- *
* Subtract a number of days from a tdate. *
\* ------------------------------------------------------------------------- */
unsigned int tdate_sub (unsigned int tdate, int amount)
{
struct tm tim;
time_t ti;
tim.tm_sec = 0;
tim.tm_min = 0;
tim.tm_hour = 4;
tim.tm_mday = tdate % 100;
tim.tm_mon = ((tdate % 10000) / 100) -1;
tim.tm_year = (tdate / 10000) - 1900;
ti = mktime (&tim);
ti = ti - (amount * 86400);
localtime_r (&ti, &tim);
return (10000 * (tim.tm_year + 1900)) +
(100 * (tim.tm_mon+1)) + tim.tm_mday;
}
/* ------------------------------------------------------------------------- *\
* FUNCTION diskdb_setlck (rec) *
* ---------------------------- *
* Sets the header/trailer lock bytes in a netload_rec structure. A record *
* will be written to the diskdb twice. The first time with the lock bytes *
* active, the second time with them removed. Another process attempting to *
* read a record will notice that either the heading or the trailing lock *
* byte has been set if the data was altered by this process at the same *
* time it was reading. It can then retry the read operation to fetch the *
* updated record. *
* *
* The netload_rec size data will be unscrewed if it has a bogus value. *
* Purely for integrity's sake it might be better to bitch out loud and stop *
* acting on the record, but that kind of checking may be better done at *
* the receive stage. *
\* ------------------------------------------------------------------------- */
void diskdb_setlck (netload_rec *rec)
{
unsigned char hiby, loby;
unsigned char lockid;
int sz;
hiby = rec->data[3];
loby = rec->data[2];
sz = loby + (hiby << 8);
if (sz > 640)
{
hiby = 2;
loby = 128;
rec->data[3] = hiby;
rec->data[2] = loby;
sz = 640;
}
lockid = rand() & 0xff;
rec->data[0] = lockid;
rec->data[sz-1] = lockid;
}
/* ------------------------------------------------------------------------- *\
* FUNCTION diskdb_locked (rec) *
* ---------------------------- *
* Determines whether a loaded record was locked. *
\* ------------------------------------------------------------------------- */
int diskdb_locked (netload_rec *rec)
{
unsigned char hiby, loby;
int sz;
hiby = rec->data[3];
loby = rec->data[2];
sz = loby + (hiby << 8);
if (sz > 640)
{
hiby = 2;
loby = 128;
rec->data[3] = hiby;
rec->data[2] = loby;
sz = 640;
}
if (rec->data[0] != rec->data[sz-1]) return 1;
return 0;
}
/* ------------------------------------------------------------------------- *\
* FUNCTION diskdb_open (host, date) *
* --------------------------------- *
* Looks for a diskdb in /var/state/n2/log matching the provided host *
* address and date. If none was found, this function will attempt to create *
* a fresh database file with the required filename. *
\* ------------------------------------------------------------------------- */
FILE *diskdb_open (unsigned long host, unsigned int date)
{
char filename[256];
char dirname[256];
char ipstr[32];
struct stat statbuf;
char *nullblock;
FILE *res;
int i;
printip (host, ipstr);
sprintf (dirname, "/var/state/n2/log/%s", ipstr);
sprintf (filename, "/var/state/n2/log/%s/%s-%u.n2db", ipstr, ipstr, date);
if (stat (dirname, &statbuf) != 0) mkdir (dirname, 0750);
if (stat (filename, &statbuf)) /* true if the file doesn't exist */
{
res = fopen (filename, "a+");
if (! res)
{
fprintf (stderr, "diskdb_open: Could not create: %s: %s\n",
filename, strerror (errno));
return NULL;
}
nullblock = (char *) calloc (1, (size_t) 92160);
for (i=0; i<10; ++i)
{
fwrite (nullblock, (size_t) 92160, 1, res);
}
free (nullblock);
fclose (res);
res = fopen (filename, "r+");
fseek (res, 0, SEEK_SET);
}
else
{
res = fopen (filename, "r+");
if (! res)
{
fprintf (stderr, "diskdb_open: Could not open: %s: %s\n",
filename, strerror (errno));
return NULL;
}
fseek (res, 0, SEEK_SET);
}
return res;
}
/* ------------------------------------------------------------------------- *\
* FUNCTION diskdb_setcurrent (host, rec) *
* -------------------------------------- *
* Writes the provided record to /var/state/n2/current atomically, then *
* calls diskdb_store to write the record to the database as well, using *
* the current date/time as an index reference. *
\* ------------------------------------------------------------------------- */
void diskdb_setcurrent (unsigned long host, netload_rec *rec)
{
char tempfilename[256];
char permfilename[256];
char ipstr[32];
FILE *f;
unsigned int date;
int index;
diskdb_now (&date, &index);
printip (host, ipstr);
sprintf (tempfilename, "/var/state/n2/tmp/%s", ipstr);
sprintf (permfilename, "/var/state/n2/current/%s", ipstr);
f = fopen (tempfilename, "w");
if (! f)
{
fprintf (stderr, "diskdb_setcurrent: Could not open: %s: %s\n",
tempfilename, strerror (errno));
return;
}
fwrite (rec, (size_t) 640, 1, f);
fclose (f);
rename (tempfilename, permfilename);
diskdb_store (host, rec, date, index);
}
/* ------------------------------------------------------------------------- *\
* FUNCTION diskdb_store (host, rec, date, index) *
* ---------------------------------------------- *
* Writes a record to the apropriate database file. *
\* ------------------------------------------------------------------------- */
void diskdb_store (unsigned long host, netload_rec *rec,
unsigned int date, int index)
{
FILE *f;
f = diskdb_open (host, date);
if (! f)
{
fprintf (stderr, "diskdb_store: Could not open diskdb\n");
return;
}
if (fseek (f, 640 * index, SEEK_SET))
{
fprintf (stderr, "diskdb_store: Failed seek offset=%i\n", 640*index);
fclose (f);
return;
}
diskdb_setlck (rec);
fwrite (rec, (size_t) 640, 1, f);
fclose (f);
}
/* ------------------------------------------------------------------------- *\
* FUNCTION diskdb_get (host, date, index) *
* --------------------------------------- *
* Reads a record from the disk database. If it runs into a lock it will *
* retry a number of times. *
\* ------------------------------------------------------------------------- */
netload_rec *diskdb_get (unsigned long host, unsigned int date, int index)
{
int valid;
int retries;
FILE *f;
size_t sz;
struct stat st;
char filename[256];
char oldfilename[256];
char dirname[256];
char ipstr[32];
netload_rec *rec;
valid = 0;
retries = 0;
printip (host, ipstr);
sprintf (filename, "/var/state/n2/log/%s/%s-%u.n2db", ipstr, ipstr, date);
f = fopen (filename, "r");
if (! f)
{
return NULL;
}
while (! valid)
{
if (fseek (f, 640 * index, SEEK_SET))
{
fprintf (stderr, "diskdb_get: Failed seek offset=%i\n", 640 * index);
fclose (f);
return NULL;
}
rec = (netload_rec *) calloc (1, sizeof (netload_rec));
if ((sz = fread (rec, 1, 640, f) != 640))
{
fprintf (stderr, "diskdb_get: Short read sz=%u\n", sz);
fclose (f);
free (rec);
return NULL;
}
rec->pos = 4;
rec->rpos = 2;
rec->eof = 0;
sz = rec_read16 (rec);
rec->pos = sz;
rec->rpos = 0;
rec->eof = 0;
if (! diskdb_locked (rec))
{
valid = 1;
}
else
{
++retries;
if (retries > 8)
{
fprintf (stderr, "diskdb_get: Stale lock, overriding\n");
valid = 1;
}
else
{
free (rec);
usleep (100);
}
}
}
fclose (f);
return rec;
}
/* ------------------------------------------------------------------------- *\
* FUNCTION diskdb_get_current (host) *
* ---------------------------------- *
* Reads the current from the disk database. If it runs into a lock it will *
* retry a number of times. *
\* ------------------------------------------------------------------------- */
netload_rec *diskdb_get_current (unsigned long host)
{
int valid;
int retries;
FILE *f;
size_t sz;
char filename[256];
char ipstr[32];
netload_rec *rec;
valid = 0;
retries = 0;
printip (host, ipstr);
sprintf (filename, "/var/state/n2/current/%s", ipstr);
f = fopen (filename, "r");
if (! f)
{
fprintf (stderr, "diskdb_get_current: Could not open: %s: %s\n",
filename, strerror (errno));
return NULL;
}
rec = (netload_rec *) calloc (1, sizeof (netload_rec));
if ((sz = fread (rec, 1, 640, f) != 640))
{
fprintf (stderr, "diskdb_get: Short read sz=%u\n", sz);
fclose (f);
free (rec);
return NULL;
}
rec->pos = 4;
rec->rpos = 2;
rec->eof = 0;
sz = rec_read16 (rec);
rec->pos = sz;
rec->rpos = 0;
rec->eof = 0;
fclose (f);
return rec;
}
/* ------------------------------------------------------------------------- *\
* FUNCTION diskdb_get_range (host, date, first, last) *
* --------------------------------------------------- *
* Reads a consecutive list of records from a single database file and *
* returns it as an array of netload_rec pointers. *
\* ------------------------------------------------------------------------- */
netload_rec **diskdb_get_range (unsigned long host, unsigned int date,
int first, int last)
{
int i;
netload_rec **res = (netload_rec **)
calloc ((last+1-first), sizeof (netload_rec *));
for (i=first; i<=last; ++i)
{
res[i] = diskdb_get (host, date, i);
}
return res;
}