1 char block_c_cvsid[] =
2 "$Id: block.c,v 1.7 2005-06-21 07:44:16 adparker Exp $";
3
4 #include <stdlib.h>
5 #include <errno.h>
6 #include <stdio.h>
7 #include <glib.h>
8 #include <string.h>
9 #include "libmisc/misc_buf.h"
10 #include "link/link.h"
11 #include "devel/block_tree/block.h"
12 #include <assert.h>
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <unistd.h>
16 #include <ftw.h>
17
18 #define FINAL_IF_NULL(name, string) \
19 \
20 if (name == NULL) \
21 { \
22 /* elog (LOG_CRIT, "Unexpected NULL pointer, %s", string); */\
23 goto final; \
24 } \
25
26 void
27 block_uid_unparse (buf_t * buf, const block_uid_t * buid, const char *indent)
28 {
29 bufprintf (buf, "\t%snode_id: %s ", indent, print_if_id (buid->node_id));
30 bufprintf (buf, "%sname: %s ", indent, buid->name);
31 bufprintf (buf, "%stotal_length: %d ", indent, buid->total_length);
32 return;
33 }
34
35 void
36 block_unparse (buf_t * buf, const void *entry, const char *indent)
37 {
38 // block_t * bi = (block_t *)entry;
39
40 block_t *block = (block_t *) entry;
41 block_uid_unparse (buf, &block->uid, indent);
42 bufprintf (buf, "%soffset: %d ", indent, block->offset);
43 bufprintf (buf, "%slength: %d", indent, block->length);
44 return;
45 }
46
47
48 // Assumes that if uid.name's are the same, then the uid.total_lengths
49 // are the same.
50 gint
51 block_uid_GCompareData (gconstpointer a, gconstpointer b, gpointer user_data)
52 {
53 block_uid_t *aa = (block_uid_t *) a;
54 block_uid_t *bb = (block_uid_t *) b;
55 gint result;
56 if ((result =
57 memcmp (&aa->node_id, &bb->node_id, sizeof (aa->node_id))) != 0)
58 return result;
59 return strcmp (aa->name, bb->name);
60 }
61
62 gint
63 block_GCompareData (gconstpointer a, gconstpointer b, gpointer user_data)
64 {
65 // negative if a < b
66 // 0 if a == b
67 // pos if a > b
68 block_t *aa = (block_t *) a;
69 block_t *bb = (block_t *) b;
70 gint result;
71 if ((result =
72 block_uid_GCompareData ((gconstpointer *) & aa->uid,
73 (gconstpointer *) & bb->uid, user_data)) != 0)
74 return result;
75
76 if ((result = (aa->offset - bb->offset)) != 0)
77 return result;
78 return aa->length - bb->length;
79 }
80
81 // Blocks with matching offsets and uids are considered equivalent.
82 // Length is ignored.
83 gint
84 block_GCompareOffsetData (gconstpointer a, gconstpointer b, gpointer user_data)
85 {
86 block_t *aa = (block_t *) a;
87 block_t *bb = (block_t *) b;
88 gint result;
89 if ((result =
90 block_uid_GCompareData ((gconstpointer *) & aa->uid,
91 (gconstpointer *) & bb->uid, user_data)) != 0)
92 return result;
93 return aa->offset - bb->offset;
94 }
95
96 // Blocks with matching UID are considered equivalent.
97 gint
98 block_GCompareUIDData (gconstpointer a, gconstpointer b, gpointer user_data)
99 {
100 block_t *aa = (block_t *) a;
101 block_t *bb = (block_t *) b;
102 gint result;
103 result = block_uid_GCompareData ((gconstpointer *) & aa->uid,
104 (gconstpointer *) & bb->uid, user_data);
105 return result;
106 }
107
108 void
109 block_GDestroyNotify (gpointer data)
110 {
111 if (data != NULL)
112 free (data);
113 return;
114 }
115
116 void
117 block_remove_array_from_tree (GArray * array, GTree * tree)
118 {
119 if (!array || !tree)
120 return;
121
122 int i;
123 for (i = 0; i < array->len; ++i)
124 {
125 block_t block = g_array_index (array, block_t, i);
126 g_tree_remove (tree, &block);
127 }
128 }
129
130 gboolean
131 block_append_helper (gpointer key, gpointer value, gpointer data)
132 {
133 GArray **array_ref = (GArray **) data;
134 block_t *block_ref = (block_t *) key;
135
136 // I want to append a copy of the block
137 *array_ref = g_array_append_val (*array_ref, *block_ref);
138
139 return FALSE; // this is required to force the traversal to continue;
140 }
141
142 // Array assumed to be allocated
143 // tree and *array_ref assumed to be non-null
144 void
145 block_append_tree_to_array (GTree * tree, GArray ** array_ref)
146 {
147 g_tree_foreach (tree, block_append_helper, array_ref);
148 return;
149 }
150
151 GArray *
152 block_tree_to_array (GTree * tree)
153 {
154 GArray *array = g_array_new (0, 1, sizeof (block_t));
155 block_append_tree_to_array (tree, &array);
156 return array;
157 }
158
159
160 // returns NULL on error
161 // don't forget to close the FILE *
162 FILE *
163 block_fopen (const char *fname, const char *opts)
164 {
165 FILE *fp = fopen (fname, opts);
166 if (fp == NULL)
167 {
168 // elog (LOG_CRIT, "Error while trying to open %s: %m", fname);
169 }
170 return fp;
171 }
172
173 // returns 0 on error
174 size_t
175 block_fread (block_t * blockp, size_t size, int items, FILE * fp)
176 {
177 size_t items_read = fread (blockp, size, items, fp);
178 if (items_read != items)
179 {
180 if (feof (fp))
181 {
182 // elog (LOG_CRIT, "Unexpected EOF while reading file");
183 }
184 if (ferror (fp) && !feof (fp))
185 {
186 // elog (LOG_CRIT, "Error while reading: %m");
187 }
188 return 0;
189 }
190 return items_read;
191 }
192
193 void
194 block_bufprint_dir (buf_t * buf, const char *blocks_dir,
195 const block_t * block)
196 {
197 bufprintf (buf, "%s/%s", blocks_dir, block->uid.name);
198 return;
199 }
200
201 void
202 block_bufprint_name (buf_t * buf, const char *blocks_dir,
203 const block_t * block)
204 {
205 block_bufprint_dir (buf, blocks_dir, block);
206 bufprintf (buf, "/%d_%d_%d",
207 block->offset, block->length, block->uid.total_length);
208 return;
209 }
210
211 // Returns -1 on error. Otherwise, it returns the size in bytes of the
212 // file.
213 int
214 block_byte_size_from_name (const char * fname)
215 {
216 struct stat file_stat;
217 if (stat (fname, &file_stat) == 0)
218 return file_stat.st_size;
219 else
220 return -1;
221 }
222
223
224 block_t * ftw_block = NULL;
225 int ftw_block_size = 0;
226 const block_t * ftw_key_block;
227
228 void
229 fread_error (FILE * fp, const char * file)
230 {
231 // OK, find out what kind of error we have here.
232 if (feof (fp))
233 elog (LOG_CRIT, "Unexpected EOR while reading %s", file);
234 else if (ferror (fp))
235 elog (LOG_CRIT, "Error while reading %s: %m", file);
236 else
237 elog (LOG_CRIT, "Unknown error while reading %s", file);
238 return;
239 }
240
241 void
242 reset_ftw_block ()
243 {
244 if (ftw_block)
245 {
246 free (ftw_block);
247 ftw_block = NULL;
248 }
249 ftw_block_size = 0;
250 }
251
252 // This is called for each file in the
253 int
254 block_find_matching_offset (const char * file, const struct stat *sb, int flag)
255 {
256 elog (LOG_NOTICE, " ");
257 FILE * fp = NULL;
258 block_t block;
259 int stop = 0;
260
261 reset_ftw_block();
262
263 if (FTW_F != flag)
264 {
265 goto done;
266 }
267
268 fp = fopen (file, "rb");
269 if (fp == NULL)
270 {
271 elog (LOG_CRIT, "Unable to open file: %s: %m", file);
272 goto done;
273 }
274
275 // nibble on the file to figure out what we have
276 size_t items_read = fread (&block, sizeof (block_t), 1, fp);
277 if (items_read != 1)
278 {
279 fread_error (fp, file);
280 goto done;
281 }
282
283 // check to see if we have a match
284 if (block_GCompareOffsetData (&block, ftw_key_block, NULL) == 0)
285 {
286 // Match. So copy over the whole thing into ftw_block
287 ftw_block_size = sb->st_size;
288 ftw_block = (block_t*) malloc (ftw_block_size);
289 rewind (fp);
290 items_read = fread (ftw_block, sb->st_size, 1, fp);
291 if (items_read != 1)
292 {
293 fread_error (fp, file);
294 reset_ftw_block ();
295 goto done;
296 }
297 stop = 1;
298 }
299
300 done:
301 if (fp != NULL)
302 fclose (fp);
303 return stop;
304 }
305
306 // calls something that allocates memory
307 // returns a pointer to a block that matches key_block's uid and offset.
308 // OR returns NULL if no matching block was found.
309 block_t *
310 block_get_matching_offset (const char * blocks_dir, const block_t * key_block)
311 {
312 // First tries to guess the name. If that doesn't work, then
313 // traverse directory structure
314 // read in each real block.
315 // See if real block matches key_block
316 // return block_structure
317 elog (LOG_INFO, " ");
318
319 ftw_key_block = key_block;
320
321 buf_t *dirname = buf_new();
322
323 block_bufprint_dir (dirname, blocks_dir, key_block);
324
325 if (ftw (dirname->buf, block_find_matching_offset, 4) < 0)
326 {
327 elog (LOG_CRIT, "ftw encountered an error on %s: %m",
328 blocks_dir);
329 }
330
331 buf_free(dirname);
332
333 if (ftw_block == NULL)
334 {
335 return NULL;
336 }
337 else
338 {
339 block_t * block = ftw_block;
340 ftw_block = NULL;
341 ftw_block_size = 0;
342 return block;
343 }
344 }
345
346 // allocates memory
347 block_t *
348 block_get_from_disk (const char *blocks_dir, const block_t * key_block)
349 {
350 struct timeval starttime;
351 gettimeofday(&starttime,NULL);
352
353 buf_t *fname = buf_new ();
354 FILE *fp = NULL;
355 block_t *data_block = NULL;
356 size_t total_size = 0;
357 size_t bytes_read = 0;
358
359 FINAL_IF_NULL (blocks_dir, "blocks_dir");
360 FINAL_IF_NULL (key_block, "key_block");
361
362 block_bufprint_name (fname, blocks_dir, key_block);
363 elog (LOG_NOTICE, "Opening file: %s", fname->buf);
364 fp = block_fopen (fname->buf, "r");
365 FINAL_IF_NULL (fp, "fp");
366 total_size = block_byte_size_from_name (fname->buf);
367 data_block = (block_t *) malloc (total_size);
368 memset (data_block, 0, total_size);
369 elog (LOG_NOTICE, "Reading file: %s", fname->buf);
370 bytes_read = block_fread (data_block, 1, total_size, fp);
371 if (bytes_read == 0)
372 {
373 free (data_block);
374 data_block = NULL;
375 goto final;
376 }
377
378
379 struct timeval fintime;
380 gettimeofday (&fintime,NULL);
381 struct timeval difftime;
382 difftime.tv_sec = fintime.tv_sec - starttime.tv_sec;
383 difftime.tv_usec = fintime.tv_usec - starttime.tv_usec;
384 elog (LOG_INFO, "FILE READ TIME difftime.tv_sec/usec :%ld, %ld, total miliseconds: %f",
385 difftime.tv_sec,
386 difftime.tv_usec,
387 (difftime.tv_sec * 1000.0) + (difftime.tv_usec / 1000.0));
388
389
390 final:
391 if (fp != NULL)
392 fclose (fp);
393 buf_free (fname);
394 return data_block;
395 }
396
397 void
398 block_guess_length (block_t * block)
399 {
400 block->length = block->uid.total_length - block->offset;
401 if (block->length > FRAG_SIZE)
402 block->length = FRAG_SIZE;
403 }
404
405
406 // Tries to delete the file and also the parent directory.
407 // Returns 0 if removed nothing.
408 // Returns 1 if removed file, but not dir
409 // Returns 2 if removed dir (so the file was either deleted
410 // or didn't exist)
411 int
412 block_delete_from_disk (const char *blocks_dir, const block_t * block)
413 {
414 elog (LOG_NOTICE, " ");
415 int result = 0;
416 buf_t *fname = buf_new ();
417 buf_t *dname = buf_new ();
418 block_bufprint_name (fname, blocks_dir, block);
419 block_bufprint_dir (dname, blocks_dir, block);
420 int errsv = 0;
421 elog (LOG_NOTICE, "Deleting file: %s", fname->buf);
422 if (remove (fname->buf) < 0)
423 {
424 //elog (LOG_CRIT, "Unable to remove file %s: %m", fname->buf);
425 }
426 else
427 {
428 result = 1;
429 }
430 elog (LOG_NOTICE, "Considering deleting parent directory: %s", dname->buf);
431 if (remove (dname->buf) < 0)
432 {
433 errsv = errno;
434 if (errsv == ENOTEMPTY)
435 {
436 // elog (LOG_NOTICE, "Parent directory not empty %s: %m", dname->buf);
437 }
438 else
439 {
440 //elog (LOG_CRIT, "Error deleted empty directory %s: %m", dname->buf);
441 }
442 }
443 else
444 {
445 result = 2;
446 }
447
448 buf_free (fname);
449 buf_free (dname);
450 return result;
451 }
452
453 // returns 1 on success
454 // returns 0 on fail
455 int
456 block_make_file_dir (const char *blocks_dir, const block_t * block)
457 {
458 int result = 0;
459 buf_t *buf = buf_new ();
460 DIR * dir = NULL;
461 FINAL_IF_NULL (blocks_dir, "blocks_dir");
462 FINAL_IF_NULL (block, "block");
463
464
465 block_bufprint_dir (buf, blocks_dir, block);
466
467 dir = opendir (buf->buf);
468 // skip if it already exists
469 if (dir != NULL)
470 {
471 elog (LOG_NOTICE, "Skipping %s", buf->buf);
472 closedir(dir);
473 result = 1;
474 goto final;
475 }
476
477 if (mkdir_with_parents (buf->buf) < 0)
478 {
479 elog (LOG_CRIT, "Failed ot make directory:%s, %m", buf->buf);
480 }
481 result = 1;
482
483 final:
484 buf_free (buf);
485 return result;
486 }
487
488 void
489 block_write_to_disk (const char *blocks_dir, const block_t * block)
490 {
491 elog (LOG_NOTICE, " ");
492 buf_t *fname = buf_new ();
493 FILE *fp = NULL;
494
495 FINAL_IF_NULL (block, "block");
496 FINAL_IF_NULL (blocks_dir, "blocks_dir");
497
498 size_t size = sizeof (block_t) + block->length;
499 block_bufprint_name (fname, blocks_dir, block);
500
501 // skip if it already exists.
502 fp = fopen (fname->buf, "r");
503 if (fp != NULL)
504 {
505 elog (LOG_NOTICE, "Skipping %s",fname->buf);
506 goto final;
507 }
508
509
510 if (!block_make_file_dir (blocks_dir, block))
511 {
512 elog (LOG_CRIT, "Failed to create file directory");
513 goto final;
514 }
515
516 fp = block_fopen (fname->buf, "w");
517 FINAL_IF_NULL (fp, "fp");
518
519 elog (LOG_NOTICE, "Writing %d bytes to %s", size, fname->buf);
520 size_t items_written = fwrite (block, size, 1, fp);
521 if (items_written != 1)
522 {
523 elog (LOG_CRIT, " Error writing block to %s:%m ", fname->buf);
524 }
525
526 final:
527 if (fp) fclose (fp);
528 buf_free (fname);
529 return;
530 }
531
532 void
533 block_generic_shutdown (void *data)
534 {
535 char *name = (char *) data;
536 elog (LOG_NOTICE, "%s shutting down.", name);
537 exit (0);
538 }
539
540
541 block_t *
542 block_new_empty ()
543 {
544 block_t *block = (block_t *) malloc (sizeof (block_t));
545 memset (block, 0, sizeof (block_t));
546 return block;
547 }
548
549 block_t
550 block_create_empty ()
551 {
552 block_t block;
553 memset (&block, 0, sizeof (block_t));
554 return block;
555 }
556
557 int
558 block_isempty (block_t * block)
559 {
560 block_t empty = block_create_empty ();
561 int result = memcmp (&empty, block, sizeof (block_t));
562 return result;
563 }
564
565 void
566 block_remove_empty_from_tree (GTree * tree)
567 {
568 block_t empty = block_create_empty();
569 g_tree_remove (tree, &empty);
570 }
571
572 GArray *
573 block_remove_empty_from_array (GArray * array)
574 {
575 int i;
576 for (i = array->len - 1; i >= 0; --i)
577 {
578 block_t block = g_array_index (array, block_t, i);
579 if (block_isempty (&block))
580
581 {
582 elog (LOG_NOTICE, "Removing index %d", i);
583 array = g_array_remove_index (array, i);
584 }
585 }
586 return array;
587 }
588
589 gint block_compare_string(gconstpointer a, gconstpointer b, gpointer user_data)
590 {
591 return strcmp((const char *)a, (const char *)b);
592 }
593
594 void
595 block_string_destroy_notify(gpointer data)
596 {
597 if (data) free(data);
598 }
599 void
600 block_array_destroy_notify(gpointer data)
601 {
602 if (data)
603 g_array_free((GArray*)data, 1);
604 }
605
606
607 // arrays in the tree are sorted
608 GTree *
609 block_array_to_array_tree(GArray * array)
610 {
611 // array contains random block_t.
612 // create a tree that contains char * to GArray * mapping.
613 // sort array
614 // iterate through array.
615 // if this is a new string, then create a new array;
616
617 GTree * tree = g_tree_new_full(block_compare_string, NULL, block_string_destroy_notify, block_array_destroy_notify);
618 g_array_sort_with_data(array, block_GCompareData, NULL);
619
620 char * previous_name = NULL;
621 int i;
622 GArray * newarray = NULL;
623 int foundone = 0;
624 for (i = 0; i < array->len; ++i)
625 {
626 block_t * block = &g_array_index(array, block_t, i);
627 // check if this is a new name
628 // insert old array if not NULL;
629 // pick up new name;
630 // create a new array
631 if ((previous_name == NULL)
632 || (strcmp(block->uid.name, previous_name) != 0))
633 {
634 ++foundone;
635 // this should be the first and only time we're inserting this name
636 if (previous_name) {
637 g_tree_replace(tree, previous_name, newarray);
638 }
639 newarray = g_array_new(0, 1, sizeof(block_t));
640 previous_name = strdup(block->uid.name);
641 }
642 g_array_append_val(newarray, *block);
643 }
644 // don't forget the last one
645 if (foundone)
646 {
647 // we have one left-over
648 g_tree_replace(tree, previous_name, newarray);
649 }
650
651 return tree;
652 }
653
654 // allocates memory
655 // accepts a GArray of block_t
656 // length must be at least one
657 // for one file
658 void
659 bufprintf_file_state(buf_t * buf, GArray * array, int segments)
660 {
661 assert(array);
662 assert(array->len > 0);
663
664 block_t first_block = g_array_index(array,block_t,0);
665
666 uint32_t total_length = first_block.uid.total_length;
667 if (segments > total_length)
668 {
669 segments = total_length;
670 }
671 div_t div_segment = div(total_length, segments);
672 int segment_size = div_segment.quot;
673 int last_segment_size = 0;
674
675 if (div_segment.rem > 0)
676 {
677 ++segment_size;
678 last_segment_size = total_length - (segment_size * (segments-1));
679 }
680 else
681 {
682 last_segment_size = segment_size;
683 }
684
685 char * graph = (char*)malloc(segments + 1);
686 memset(graph,0,segments+1);
687 memset(graph,'.',segments);
688
689 uint32_t first= 0;
690 uint32_t last = 0;
691 int i;
692 for (i = 0; i <= array->len; ++i)
693 {
694 block_t block;
695 if (i < array->len)
696 block = g_array_index(array,block_t,i);
697 else
698 {
699 block.offset = total_length + 1;
700 block.length = 0;
701 }
702
703 if (last != block.offset)
704 {
705 // gap detected
706 // [first - last] is continuous
707 // mark slots containing first up to and including (last - 1) as full;
708 int first_slot = div(first, segment_size).quot;
709 int first_on_boundary = div(first,segment_size).rem ? 0 : 1;
710 int last_slot = div(last, segment_size).quot;
711 int last_on_boundary = div(last,segment_size).rem ? 0 : 1;
712 int block_slot = div(block.offset,segment_size).quot;
713
714 int j;
715 // optimistically mark everything as full except last slot
716 for (j = first_slot; j < last_slot; ++j)
717 {
718 graph [ j ] = '|';
719 }
720 // if first not on boundary, then mark as partial
721 if (!first_on_boundary)
722 {
723 if (first_slot < segments)
724 graph [ first_slot ] = ':';
725 }
726 // if the last guy is on a boundry then don't count it, else it's partial
727 if (last_on_boundary){
728 if (last_slot < segments)
729 graph [ last_slot ] = '.';
730 }
731 else {
732 if (last_slot < segments)
733 graph [last_slot] = ':';
734 }
735 // CHECK FOR LAST SEGMENT
736 if (( last_slot == (segments - 1)) // this is the last segment
737 && ((block.offset + block.length) == total_length) // we're at the end
738 && ((first_slot < last_slot) // first is before or on boundary
739 || (first_on_boundary)))
740 {
741 // we're full
742 if (last_slot < segments)
743 graph [ last_slot ] = '|';
744 }
745
746 // now, do the same, but with [ last - block.offset ]
747 int k;
748 // mark everything as empty except for last slot
749 if (i < array->len){
750 for (k = last_slot + 1; k < block_slot; ++k)
751 {
752 if (k < segments)
753 graph [k] = '.';
754 }
755 }
756 first = block.offset;
757 last = first + block.length;
758 }
759 else
760 {
761 // last == block,.offset. so set last to be block.offset + length
762 last = block.offset + block.length;
763 }
764 }
765 // now , let's print stuff to the buffer.
766 // 58% 58/100 [**--.--..]
767 bufprintf(buf, "[%s]", graph);
768 free(graph);
769
770 }
771
772
773 gboolean
774 block_pretty_traverse(gpointer key, gpointer value, gpointer data)
775 {
776 char * name = (char*)key;
777 GArray * array = (GArray *)value; // sorted
778 buf_t * buf = (buf_t*)data;
779 // I want it to look like:
780 // filename 96% 96/100 [...---.*.*.]
781 if (strcmp(name,"") != 0)
782 {
783 bufprintf(buf, "\t%-15s ", name);
784 bufprintf_file_state(buf, array, 32);
785 bufprintf(buf,"\n");
786 }
787 return FALSE;
788 }
789
790
791
792 void
793 block_pretty_bufprintf_array(buf_t * buf, GArray * array)
794 {
795 GTree * tree = block_array_to_array_tree(array);
796 g_tree_foreach(tree, block_pretty_traverse, buf);
797 g_tree_destroy(tree);
798 }
799
800
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.