~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
cvs/emstar/devel/block_tree/src/block.c


  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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.