Add proper per-file copyright notices/licenses and top-level license.
[bluesky.git] / TBBT / trace_play / rfs_c_age.c
1 /* rfs_age_unit_base.c */
2 #include <sys/vfs.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5 #include <errno.h>
6 #include <stdio.h>
7 #include "rfs_assert.h"
8 #include "profile.h"
9 #define MKDIR 1
10 #define RMDIR 2
11 #define CREATE 3
12 #define REMOVE 4
13 #define WRITE 5
14 #define TRUNCATE 6
15
16 #define MAX_FILES 400000
17 #define MAX_DIRS  100000
18 #define FILE_FH_HTABLE_SIZE MAX_FILES
19 #define MAX_NAMELEN 512
20 #define MAX_PLAY_PATH_SIZE 256
21 //#define MAX_COMMAND_LEN (MAX_PLAY_PATH_SIZE+16)
22 //#define NFS_MAXDATA 4096
23 #define NFS_MAXDATA 32768
24 #define TRACE_FH_SIZE 64
25
26 #define FH_T_FLAG_FREE 0
27 #define FH_T_FLAG_IN_USE 1
28 #define IS_FILE 0
29 #define IS_DIR 1
30 #define EXIST 0
31 #define NON_EXIST 1
32 #define COMPLETE 3
33 #define ACTIVE 0
34 #define INACTIVE 1
35 #define DONT_CARE 2
36
37 int EVEN_CHUNK_SIZE = 0;
38 int STAGE_NUM = 10;
39
40 static char ftypename[3][32] = {"FILE", "DIR", "FTYPE_DONT_CARE"};
41 static char activename[3][32] = {"ACTIVE", "INACTIVE", "ACTIVE_DONT_CARE"};
42 static char existname[4][32] = {"EXIST", "NON_EXIST", "EXIST_DONT_CARE", "COMPLETE"};
43
44 typedef struct {
45     char flag;
46         char ftype;
47         char exist_flag;
48         int psfh;
49         int size;
50         int cur_size;
51         int accumulated_write_size;
52     //char trace_fh [TRACE_FH_SIZE+1];
53     char path[MAX_PLAY_PATH_SIZE];
54 } fh_t;
55
56 typedef struct {
57         char name[32];
58         fh_t * fh;
59         //struct generic_entry * htable;
60         int fh_size;
61         int fh_max;
62         int active_fh_max;
63         //int index;
64         //int htable_size;
65 } fh_info_t;
66
67 fh_info_t obj_fh;
68 profile_t read_line_profile, fgets_profile;
69 char trace_file[MAX_NAMELEN];
70 FILE * profile_fp = NULL;
71 char testdir[MAX_NAMELEN];
72
73 int active_obj_num = 0;
74 int exist_active_obj_num = 0;
75 static int active_file_num = 0, active_dir_num =0, age_file_num = 0, age_dir_num = 0;
76
77 int age_create_num = 0;
78 int age_mkdir_num = 0;
79 int assure_create_num = 0;
80 int assure_mkdir_num = 0;
81 int age_write_num = 0;
82 int nonage_write_num = 0;
83 int overlap_write_num = 0;
84
85 int fs_size_MB = 0, fs_size = 0;
86 int rfs_debug = 0;
87
88
89 int ACTIVE_RATIO;
90 int FILE_RATIO = 50;
91 int WRITE_CHUNK_NUM;
92 int MAX_FS_SIZE_MB = 1000000; 
93 int DISK_FRAGMENT_SIZE = 4096;
94 int DISK_FRAGMENT_SIZE_MASK = 0xFFFFF000;
95
96 int MIN_WRITE_SIZE;
97
98 int aging_dirs ()
99 {
100
101 }
102
103 int f()
104 {};
105
106 int init_profile_variables()
107 {
108         init_profile ("read_line profile", &read_line_profile);
109         init_profile ("fgets profile", &fgets_profile);
110 }
111
112 int init_fh_info (char * name, fh_info_t * fh_infop, int fh_size, int htable_size)
113 {
114         int i;
115
116         RFS_ASSERT (strlen(name) < sizeof(fh_infop->name));
117         strcpy (fh_infop->name, name);
118         fh_infop->fh_max = 0;
119         //fh_infop->index = 0;
120         fh_infop->fh_size = fh_size;
121         //fh_infop->htable_size = htable_size;
122         fh_infop->fh = (fh_t *)malloc (sizeof(fh_t)*fh_size);
123         RFS_ASSERT (fh_infop->fh);
124         //fh_infop->htable = malloc (sizeof(struct*generic_entry)*htable_size);
125         //RFS_ASSERT (fh_infop->htable);
126         printf("initialize %s size %d bytes\n", 
127                 //name, sizeof(fh_t)*fh_size + sizeof(struct*generic_entry)*htable_size);
128                 name, sizeof(fh_t)*fh_size);
129
130         for (i=0; i<fh_size; i++)
131                 fh_infop->fh[i].flag = FH_T_FLAG_FREE;
132 }
133
134 int init()
135 {
136 //      init_fh_info ("file_fh", &file_fh, MAX_FILES, MAX_FILES);
137 //      init_fh_info ("dir_fh", &dir_fh, MAX_DIRS, MAX_DIRS);
138         init_fh_info ("obj_fh", &obj_fh, MAX_FILES+MAX_DIRS, MAX_FILES+MAX_DIRS);
139 }
140
141 int add_fh_t (fh_info_t * fh_table, char * path, int sfh, int psfh, int size, int ftype, int exist_flag, int active_flag)
142 {
143         int i;
144
145         if (size == -1) 
146                 fs_size += DISK_FRAGMENT_SIZE;
147         else {
148                 fs_size += ((size+DISK_FRAGMENT_SIZE-1) & DISK_FRAGMENT_SIZE_MASK);
149                 if (size > (DISK_FRAGMENT_SIZE*12))     // first indirect block
150                         fs_size += DISK_FRAGMENT_SIZE;
151         }
152         if (fs_size > 1000000) {
153                 fs_size_MB += fs_size/1000000;
154                 fs_size = fs_size % 1000000;
155         }
156
157         RFS_ASSERT (sfh >0);
158
159         if (active_flag == ACTIVE)
160                 active_obj_num ++;
161         else
162                 RFS_ASSERT (sfh >= fh_table->active_fh_max);
163
164         if (rfs_debug)
165                 printf ("add to %s path %s sfh %d size %d %s %s %s\n", fh_table->name, path, sfh, size, 
166                 ftypename[ftype], existname[exist_flag], activename[active_flag]);
167
168         RFS_ASSERT ( (sfh>=0) && (sfh<fh_table->fh_size) );
169         RFS_ASSERT (fh_table->fh[sfh].flag==FH_T_FLAG_FREE);
170         fh_table->fh[sfh].flag = FH_T_FLAG_IN_USE;
171         if (sfh >= fh_table->fh_max)
172                 fh_table->fh_max = sfh+1;
173         RFS_ASSERT (strlen(path)<MAX_PLAY_PATH_SIZE);
174         strcpy (fh_table->fh[sfh].path, path);
175         fh_table->fh[sfh].psfh = psfh;
176         fh_table->fh[sfh].size = size;
177         fh_table->fh[sfh].cur_size = 0;
178         fh_table->fh[sfh].accumulated_write_size = 0;
179         fh_table->fh[sfh].ftype = ftype;
180         fh_table->fh[sfh].exist_flag = exist_flag;
181         if (active_flag == ACTIVE) {
182                 if (ftype == IS_FILE)
183                         active_file_num ++;
184                 else {
185                         RFS_ASSERT (ftype== IS_DIR);
186                         active_dir_num ++;
187                 }
188         } else {
189                 if (ftype == IS_FILE)
190                         age_file_num ++;
191                 else {
192                         RFS_ASSERT (ftype== IS_DIR);
193                         age_dir_num ++;
194                 }
195         }
196         //print_fh_map(fh_table);
197 }
198
199
200 int loop_write (int fd, char * buf, int buflen)
201 {
202     int ret;
203     int pos = 0;
204
205     while (1) {
206         ret = write (fd, buf+pos, buflen-pos);
207
208         if (ret == -1) {
209                         RFS_ASSERT (errno == ENOSPC);
210                         fflush(stdout);
211             perror ("loop write");
212                         check_free_blocks(0);
213                         return -1;
214         }
215         if (ret == buflen-pos)
216             break;
217         pos += ret;
218     }
219     return 0;
220 }
221
222 int assure_exist(int sfh, char * path, int ftype_flag)
223 {
224         char name[MAX_NAMELEN];
225         int ret;
226         char *p, *q;
227         int non_exist_flag = 0;
228         int count=0;
229         struct stat st;
230
231         if (rfs_debug)
232                 printf("assure_exist %s\n", path);
233
234         ret = stat (path, &st);
235         if (ret == 0) {
236                 if (ftype_flag == IS_DIR) {
237                         RFS_ASSERT (st.st_mode & S_IFDIR);
238                         RFS_ASSERT (!(st.st_mode & S_IFREG));
239                 } else {
240                         RFS_ASSERT (st.st_mode & S_IFREG);
241                         RFS_ASSERT (!(st.st_mode & S_IFDIR));
242                 }
243                 return 0;
244         }
245         if (errno!=ENOENT) {
246                 perror(path);
247         }
248         //RFS_ASSERT (errno == ENOENT);
249         
250         p = path;
251         q = name;
252         if (*p=='/') {
253                 *q='/';
254                 p++;
255                 q++;
256         }
257         while (count++<100) {
258                 /* copy the next component from path to name */
259                 for (; *p!=0 && *p!='/'; p++, q++ ) 
260                         *q = *p;
261                 *q = 0;
262                 ret = stat (name, &st);
263                 if (ret == -1) {
264                         if (errno != ENOENT)
265                                 perror (name);
266                         RFS_ASSERT (errno == ENOENT)
267                         if ((*p)==0 && (ftype_flag==IS_FILE)) {
268                                 ret = creat (name, S_IRWXU);
269                                 if (ret == -1)
270                                         perror (name);
271                                 RFS_ASSERT (ret >=0);
272                                 assure_create_num ++;
273                                 if (rfs_debug)
274                                         printf("sfh %d create %s\n", sfh, name);
275                                 close(ret);
276                         } else {
277                                 ret = mkdir (name, S_IRWXU);
278                                 if (ret == -1)
279                                         perror (name);
280                                 RFS_ASSERT (ret >=0);
281                                 assure_mkdir_num ++;
282                                 if (rfs_debug) {
283                                         if (*p==0) 
284                                                 printf("sfh %d mkdir %s\n", sfh, name);
285                                         else
286                                                 printf("sfh %d middle mkdir %s\n", sfh, name);
287                                 }
288                                 RFS_ASSERT (ret ==0);
289                         }
290                 }
291                 if ((*p)=='/') {
292                         *q = '/';
293                         p++; q++;
294                 } else {
295                         RFS_ASSERT ((*p)==0)
296                         return 0;
297                 }
298         }
299         RFS_ASSERT (0);
300 }
301
302
303 int print_fh_map(fh_info_t * fhp)
304 {
305         int i;
306         int num = 0;
307         int active_obj_num = 0;
308
309
310         for (i=0; i<fhp->fh_max; i++) {
311                 if (fhp->fh[i].flag == FH_T_FLAG_IN_USE) {
312                         num ++;
313                         if (i < fhp->active_fh_max)
314                                 active_obj_num++;
315
316                         if (rfs_debug)
317                                 printf("%s[%d] %s %s %s\n", fhp->name, i, fhp->fh[i].path, ftypename[fhp->fh[i].ftype], existname[fhp->fh[i].exist_flag]);
318                 }
319         }
320         fprintf(stderr, "fh_max %d active_fh_max %d, in_use_num %d entries active_obj_num %d \n", fhp->fh_max, fhp->active_fh_max, num, active_obj_num);
321 }
322
323 void read_fh_map_line_skimmer (char * buf)
324 {
325         char * p;
326         char name[MAX_NAMELEN];
327         int psfh, sfh, size;
328         char filename[MAX_NAMELEN];
329
330         sfh = 0;
331         if (!strncmp(buf, "::DIR ", strlen("::DIR "))) {
332                 strcpy (name, testdir);
333                 if (buf[6]=='/') {
334                         sscanf(buf, "::DIR %s %d\n", name+strlen(name), &sfh);
335                         add_fh_t (&obj_fh, name, sfh, -1, -1, IS_DIR, NON_EXIST, ACTIVE);
336                 } /* else { 
337                         RFS_ASSERT (!strncmp(buf,"::DIR Fake 1\n", strlen("::DIR Fake 1\n")));
338                         sfh = 1;
339                         add_fh_t (&obj_fh, name, sfh, -1, -1, IS_DIR, EXIST, ACTIVE);
340                         exist_active_obj_num ++;
341                 } */
342         } else {
343
344                 if (!strncmp(buf, "::TBDIR", strlen("::TBDIR"))) 
345                         return; 
346
347                 p = strstr(buf, "parent");
348                 RFS_ASSERT (p);
349                 sscanf(p, "parent %d\n", &psfh);
350                 RFS_ASSERT (obj_fh.fh[psfh].flag == FH_T_FLAG_IN_USE);
351                 p = strstr(p, "name");
352                 RFS_ASSERT (p);
353                 if (!strncmp(p, "name xx", strlen("name xx"))) {
354                         sscanf(p, "name xx-%s sfh %d size %x", filename, &sfh, &size);
355                         //printf ("name xx-%s sfh %d\n", filename, sfh);
356                 } else {
357                         sscanf(p, "name \"%s sfh %d size %x", filename, &sfh, &size);
358                         //printf ("name %s sfh %d\n", filename, sfh);
359                         filename[strlen(filename)-1]=0;
360                 }
361                 strcpy (name, obj_fh.fh[psfh].path);    
362                 strcat (name, "/");
363                 strcat (name, filename);
364                 add_fh_t (&obj_fh, name, sfh, psfh, size, IS_FILE, NON_EXIST, ACTIVE);
365         }
366 }
367
368 void read_fh_map_line_ls (char * buf)
369 {
370         static int sfh = 2;
371         int size;
372         char name[MAX_NAMELEN];
373         char * p = name;
374         
375         strcpy (name, testdir);
376         strcat (name, "/");
377         if (strchr(buf, ' ')) {
378                 sscanf(buf, "%d %s\n", &size, p+strlen(name));
379                 add_fh_t (&obj_fh, name, sfh, -1, size, IS_FILE, NON_EXIST, ACTIVE);
380         } else {
381                 sscanf(buf, "%s\n", p+strlen(name));
382                 add_fh_t (&obj_fh, name, sfh, -1, -1, IS_DIR, NON_EXIST, ACTIVE);
383         };
384         sfh ++;
385 }
386
387 void read_fh_map (char * fh_map_file)
388 {
389         FILE * fp;
390         int i = 0;
391         char buf[1024];
392         int lineno = 0;
393         int fh_map_debug =0;
394 #define FH_MAP_FORMAT_SKIMMER   0
395 #define FH_MAP_FORMAT_LS                1
396         int fh_map_format;
397
398         if (strstr(fh_map_file, ".ski"))
399                 fh_map_format = FH_MAP_FORMAT_SKIMMER;
400         else
401                 fh_map_format = FH_MAP_FORMAT_LS;
402
403         fp = fopen(fh_map_file, "r");
404         if (!fp) {
405                 printf ("can not opern %s\n", fh_map_file);
406                 perror("open");
407                 exit (0);
408         }
409         RFS_ASSERT (fp!=NULL);
410         
411
412         memset(buf, 0, sizeof(buf));
413
414         while (fgets(buf, 1024, fp)) {
415                 RFS_ASSERT (fh_map_debug==0);
416                 lineno ++;
417                 if (rfs_debug)
418                         printf ("line %d %s", lineno, buf);
419                 if (lineno % 10000==0)
420                         printf("%d fh_map entry read\n", lineno);
421                 if (fh_map_format == FH_MAP_FORMAT_SKIMMER)
422                         read_fh_map_line_skimmer(buf);
423                 else 
424                         read_fh_map_line_ls (buf);
425         }
426                         
427         fclose(fp);
428         obj_fh.active_fh_max  = obj_fh.fh_max;
429         if (fh_map_debug) {
430                 print_fh_map (&obj_fh);
431         }
432 }
433
434 int print_usage()
435 {
436         printf("\n\nagefs fmt4 HOLDER_NUM HOLDER_SIZE DISK_FRAGMENT_SIZE testdir\n");
437         printf("Note: fmt4 is used to initialize the holders in a logical partition before starting writing aged files in a specific pattern as by fmt3 command\n");
438
439         printf("\n\nagefs fmt3 aged_file CHUNK_SIZE CHUNK_DISTANCE CHUNK_NUM START_BNO HOLDER_SIZE HOLDER_NUM DISK_FRAGMENT_SIZE testdir\n");
440         printf("Note: one file is written as CHUNK_NUM number of continuous chunks on disk, each chunk is of CHUNK_SIZE blocks, the distance between two adjacent chunks is CHUNK_DISTANCE blocks\n");
441
442         printf("\n\nagefs fmt2 size1 .. size_n num testdir\n");
443         printf("Note: N file is writen interleavingly for _num_ times, each time _size1_ bytes is written to file1, _size2_ bytes is written to file2, _sizen_ bytes is written to filen\n");
444
445         printf("\n\nagefs EVEN_CHUNK_SIZE FILE_RATIO ACTIVE_RATIO WRITE_CHUNK_NUM MAX_FS_SIZE_MB STAGE_NUM fh_path_map testdir\n");
446         printf("Note: EVEN_CHUNK_SIZE: if 1, each file is chopped to equal size chunks, if 0, each file size is chopped randomly but with the average size to be CHUNK_SIZE");
447         printf("          FILE_RATIO: percentage of number of inactive files over number of inactive file system objects\n");
448         printf("      ACTIVE_RATIO: percentage of number of active file system objects over all file system objects\n");
449         printf("      WRITE_CHUNK_NUM: when a file is initialized, it is written in several open-close session interleved with writes to other files. Except small files where file_size/WRITE_CHUNK_SIZE is less than DISK_FRAGMENT_SIZE, each open-close session on the average write (file_size/WRITE_CHUNK_NUM) bytes. \n");
450         printf("          MAX_FS_SIZE_MB: another condition to stop initialization, either all active file is initialized, or max file system size is reached\n");
451         printf("          STAGE_NUM: divide the writing of files into several stages, each stage finish initialization of some of the files. The bigger the STAGE_NUM, the less concurrency is there\n");
452 }
453
454 inline char * read_line (int disk_index)
455 {
456         static FILE * fp=NULL;
457         static int start=0;
458         static int start_disk_index=0;
459         int i;
460         static int finish_flag = 0;
461
462 #define READ_LINE_BUF_SIZE 1000
463 #define READ_LINE_LENGTH 32
464
465         static char line_buf[READ_LINE_BUF_SIZE][READ_LINE_LENGTH];
466         start_profile (&read_line_profile);
467
468         if (fp==NULL) {
469                 if (strcmp(trace_file, "stdin")) {
470                         fp = fopen(trace_file, "r");
471                         if (!fp) {
472                                 printf("can not open files %s\n", fp);
473                                 perror("open");
474                         }
475                 } else {
476                         fp = stdin;
477                 }
478                 RFS_ASSERT (fp!=NULL);
479                 for (i=0; i<READ_LINE_BUF_SIZE; i++) {
480                         start_profile(&fgets_profile);
481                         if (!fgets(line_buf[i], READ_LINE_LENGTH, fp)) {
482                                 RFS_ASSERT (0);
483                         }
484                         end_profile(&fgets_profile);
485                         //printf ("read_line, line_buf[%d]:%s", i, line_buf[i]);
486                 }
487         }
488         
489         RFS_ASSERT (disk_index <= start_disk_index+READ_LINE_BUF_SIZE)
490         if (disk_index==(start_disk_index+READ_LINE_BUF_SIZE)) {
491                 if (finish_flag) {
492                         return NULL;
493                 }
494                 start_profile(&fgets_profile);
495                 if (!fgets(line_buf[start], READ_LINE_LENGTH, fp)) {
496                         end_profile(&fgets_profile);
497                         fclose(fp);
498                         finish_flag = 1;
499                         return NULL;
500                 }
501                 end_profile(&fgets_profile);
502                 //printf ("read_line, line_buf[%d]:%s", start, line_buf[start]);
503                 start = (start+1) % READ_LINE_BUF_SIZE;
504                 start_disk_index ++;
505         }
506         RFS_ASSERT (disk_index < start_disk_index+READ_LINE_BUF_SIZE)
507         i = (start+disk_index-start_disk_index)%READ_LINE_BUF_SIZE;
508
509         end_profile (&read_line_profile);
510         return (line_buf[i]);
511 }
512
513 int print_result()
514 {
515         struct statfs stfs;
516         int ret;
517         static struct statfs first_stfs;
518         static int first_entry = 1;
519
520         ret = statfs (testdir, &stfs);
521         RFS_ASSERT (ret == 0);
522         if (first_entry) {
523                 first_entry = 0;
524                 first_stfs = stfs;
525         }
526
527         fprintf(stderr, "active_file_num %d active_dir_num %d age_file_num %d age_dir_num %d\n",
528                 active_file_num, active_dir_num, age_file_num, age_dir_num);
529         fprintf(stderr, "number of used file nodes %d, used (4K) blocks in fs %d (%d MB)\n", first_stfs.f_ffree-stfs.f_ffree, first_stfs.f_bfree - stfs.f_bfree, (first_stfs.f_bfree-stfs.f_bfree)/(1000000/DISK_FRAGMENT_SIZE));
530         fprintf(stderr, "assure_create_num %d assure_mkdir_num %d\n", assure_create_num, assure_mkdir_num);
531 }
532
533 typedef struct {
534     int     pcnt;       /* percentile */
535     int     size;       /* file size in KB */
536 } sfs_io_file_size_dist;
537
538 sfs_io_file_size_dist Default_file_size_dist[] = {
539     /* percentage   KB size */
540 #ifdef notdef
541         {   100,    128},                       
542     {    94,     64},           /*  4% */
543     {    97,    128},           /*  3% */
544 #endif
545     {    33,      1},           /* 33% */
546     {    54,      2},           /* 21% */
547     {    67,      4},           /* 13% */
548     {    77,      8},           /* 10% */
549     {    85,     16},           /*  8% */
550     {    90,     32},           /*  5% */
551     {    94,     64},           /*  4% */
552     {    97,    128},           /*  3% */
553     {    99,    256},           /*  2% */
554     {   100,   1024},           /*  1% */
555     {     0,      0}
556 };
557
558 /*
559  * For a value between 0-99, return a size based on distribution
560  */
561 static int
562 get_file_size()
563 {
564         static file_array_initialized = 0;
565         static int file_size_array[100];
566         int i;
567
568         i = random() % 100;
569
570     if (i < 0 || i > 99)
571     return (0);
572
573     if (file_array_initialized == 0) {
574             int j, k;
575         for (j = 0, k = 0; j < 100; j++) {
576                 if (j >= Default_file_size_dist[k].pcnt &&
577                 Default_file_size_dist[k + 1].size != 0)
578             k++;
579                 file_size_array[j] = Default_file_size_dist[k].size * 1024;
580         }
581         file_array_initialized++;
582     }
583     return (file_size_array[i]);
584 }
585
586 int range_random(int min, int max)
587 {
588         int i;
589         i = (random()%(max-min)) + min;
590         return i;
591 }
592
593 /* answer 1 with a probability of percent/100 */
594 int decide(int percent)
595 {
596         int i = random()%100;
597         if (i<percent)
598                 return 1;
599         else
600                 return 0;
601 }
602
603 int select_obj (fh_info_t * fhp, int ftype, int exist_flag, int active_flag, int min, int max)
604 {
605         int i;
606         int sfh, count = 0;
607
608         //printf ("select_obj %s %s %s\n", ftypename[ftype], existname[exist_flag], activename[active_flag]);
609         if (active_flag == ACTIVE) {
610                 sfh = range_random (0, fhp->active_fh_max);
611                 for (i=0; i<fhp->active_fh_max; i++) {
612                         if ((fhp->fh[sfh].flag == FH_T_FLAG_IN_USE) &&
613                                 ((ftype==DONT_CARE) || (ftype ==fhp->fh[sfh].ftype)) &&
614                                 ((exist_flag==DONT_CARE) || (fhp->fh[sfh].exist_flag == exist_flag))) {
615                                 return sfh;
616                                 }
617                         sfh = (sfh+1) % fhp->active_fh_max;
618                 }
619         } else {
620                 //min = 0;
621                 //max = fhp->fh_max;
622                 //printf ("select_obj min %d max %d\n", min, max);
623                 RFS_ASSERT (active_flag == DONT_CARE);
624                 RFS_ASSERT (exist_flag == EXIST);
625                 sfh = range_random (min, max);
626                 for (i=min; i<max; i++) {
627                 //      printf("check %d\n", sfh);
628                         RFS_ASSERT ((sfh>=min) && (sfh<max));
629                         if ((fhp->fh[sfh].flag == FH_T_FLAG_IN_USE) &&
630                             ((ftype==DONT_CARE) || (fhp->fh[sfh].ftype == ftype)) &&
631                                 (fhp->fh[sfh].exist_flag == EXIST)) {
632                                 return sfh;
633                         }
634                         sfh++;
635                         if (sfh==max)
636                                 sfh = min;
637                 }
638         }
639 /*
640         for (i=min; i<max; i++) {
641                 if ((fhp->fh[i].flag == FH_T_FLAG_IN_USE) &&
642                         (fhp->fh[i].ftype == IS_FILE)                           ) {
643                         if (fhp->fh[i].exist_flag == EXIST) {
644                                 printf ("actually %d\n", i);
645                         }
646                         RFS_ASSERT (fhp->fh[i].exist_flag != EXIST);
647                         RFS_ASSERT (fhp->fh[i].exist_flag == COMPLETE);
648                 }
649         }
650 */
651         return -1;
652 }
653
654 /* append "size" to file "path" */
655 int append_file (int sfh, char * path, int size)
656 {
657         int fd;
658         int written_bytes = 0;
659         int ret;
660 #define BUF_SIZE 32768
661         static char buf[BUF_SIZE];
662
663         if (rfs_debug)
664                 printf ("sfh %d append_file %s size %d\n", sfh, path, size);
665
666         fd = open (path, O_WRONLY|O_APPEND);
667         if (fd==-1)
668                 perror(path);
669         RFS_ASSERT (fd > 0);
670         
671         while (written_bytes+NFS_MAXDATA < size) {
672                 ret = loop_write (fd, buf, NFS_MAXDATA);
673                 RFS_ASSERT (ret!=-1);
674                 written_bytes += NFS_MAXDATA;
675         }
676         ret = loop_write (fd, buf, size-written_bytes);
677         RFS_ASSERT (ret!=-1);
678         close(fd);
679 }
680
681 int get_write_size (int target_size, int cur_size)
682 {
683         int i;
684
685         if (target_size - cur_size < MIN_WRITE_SIZE)
686                 return (target_size - cur_size);
687
688         /* target_size/WRITE_CHUNK_NUM would be the average value of i */
689         if (target_size < WRITE_CHUNK_NUM) {
690                 i = MIN_WRITE_SIZE;
691         } else {
692
693                 if (EVEN_CHUNK_SIZE)
694                         i = target_size/WRITE_CHUNK_NUM;
695                 else
696                         i = random() % (2*(target_size/WRITE_CHUNK_NUM));
697
698                 if (i < MIN_WRITE_SIZE)
699                         i = MIN_WRITE_SIZE;
700         }
701
702         if (i > (target_size - cur_size))
703                 i = target_size - cur_size;
704
705         return i;
706 }
707
708 FILE * fplog;
709
710
711 int CHUNK_SIZE;
712 int CHUNK_DISTANCE;
713 int CHUNK_NUM;
714 int START_BNO;
715 int HOLDER_NUM;
716 int HOLDER_SIZE;
717 int INDIRECT_FANOUT;
718 char agename[1024];
719
720 #define MAX_DISK_FRAGMENT_SIZE 4096
721 #define MAX_HOLDER_SIZE 10
722 #define HOLDER_DIR_NUM 1
723 #define DUMMY_FILE_COUNT 1000
724
725 main4(int argc, char ** argv)
726 {
727         int i, j;
728         char name[256];
729         char cmd[1024];
730         char * buf;
731         int fd, ret;
732         char testdir[1024];
733
734         if (argc!=6) {
735                 print_usage();
736                 return;
737         }
738         i = 2;
739         HOLDER_NUM = atoi(argv[i++]);
740         HOLDER_SIZE = atoi(argv[i++]);
741         DISK_FRAGMENT_SIZE = atoi(argv[i++]);
742         RFS_ASSERT (DISK_FRAGMENT_SIZE <= MAX_DISK_FRAGMENT_SIZE);
743         DISK_FRAGMENT_SIZE_MASK = ~(DISK_FRAGMENT_SIZE-1);
744         RFS_ASSERT ((DISK_FRAGMENT_SIZE_MASK == 0xFFFFF000) ||
745                                 (DISK_FRAGMENT_SIZE_MASK == 0xFFFFFC00)         );
746         strcpy (testdir, argv[i]);
747
748         fprintf(fplog, "main4: initialize the holders HOLDER_NUM %d HOLDER_SIZE %d DISK_FRAGMENT_SIZE %d testdir %s\n",
749                         HOLDER_NUM, HOLDER_SIZE, DISK_FRAGMENT_SIZE, testdir);
750         fflush(fplog);
751
752         buf = (char *)malloc (HOLDER_SIZE*DISK_FRAGMENT_SIZE);
753         RFS_ASSERT (buf);
754
755         /* create some dummy files */
756         for (i=0; i<DUMMY_FILE_COUNT; i++) {
757                 memset (name, 0, sizeof(name));
758                 sprintf(name, "%s/dummy%d", testdir, i);
759                 fd = creat (name, S_IRWXU);
760                 if (fd == -1) {
761                         perror(name);
762                         exit(-1);
763                 }
764                 close (fd);
765         }
766
767         /* create directories */
768         if (HOLDER_DIR_NUM !=1) {
769                 for (i=0; i<HOLDER_DIR_NUM; i++) {
770                         memset (name, 0, sizeof(name));
771                         sprintf(name, "%s/%d", testdir, i);
772                         ret = mkdir (name, S_IRWXU);
773                         if (ret == -1) {
774                                 perror(name);
775                                 exit(-1);
776                         }
777                 }
778         }
779
780         /* create regular files */
781         for (j=0; j<HOLDER_DIR_NUM; j++) {
782                 for (i=0; i<HOLDER_NUM/HOLDER_DIR_NUM; i++) {
783                         if (HOLDER_DIR_NUM == 1)  
784                                 sprintf(name, "%s/%d", testdir, i);
785                         else
786                                 sprintf(name, "%s/%d/%d", testdir, j, i);
787                         fd = open (name, O_CREAT|O_WRONLY);
788                         if (fd == -1) {
789                                 perror(name);
790                                 exit(-1);
791                         }
792                         ret = loop_write (fd, buf, HOLDER_SIZE*DISK_FRAGMENT_SIZE);
793                         close (fd);
794                         if (ret == -1) 
795                                 break;
796                 }
797         }
798
799 #ifdef notdef
800         /* delete the dummy files */
801         for (i=0; i<DUMMY_FILE_COUNT; i++) {
802                 memset (name, 0, sizeof(name));
803                 sprintf(name, "%s/dummy%d", testdir, i);
804                 ret = unlink (name);
805                 if (ret == -1) {
806                         perror(name);
807                         exit(-1);
808                 }
809         }
810 #endif
811 }
812
813 int append_space_occupier()
814 {
815         static char name [1024];
816         static FILE * fp = NULL;
817         char buf[MAX_DISK_FRAGMENT_SIZE];
818         int ret;
819         if (fp == NULL) {
820                 sprintf(name, "%s/space_ocuupier", testdir);
821                 fp = fopen (name, "a+");
822                 RFS_ASSERT (fp!= NULL);
823                 ret = fwrite (buf, DISK_FRAGMENT_SIZE, 1, fp);
824                 if (ret != 1) {
825                         perror("append space occupier");
826                 }
827                 fclose (fp);
828                 fp = NULL;
829         };
830         ret = fwrite (buf, DISK_FRAGMENT_SIZE, 1, fp);
831         if (ret != 1) {
832                 perror("append space occupier");
833         }
834         RFS_ASSERT (ret == 1);
835 }
836
837 int create_one_dummy_file()
838 {
839         int i, fd, ret;
840         static int index = 0;
841         static char name[1024];
842         struct stat st;
843
844         for (i=0; i<DUMMY_FILE_COUNT; i++) {
845                 index = (index+1) % DUMMY_FILE_COUNT;
846                 sprintf(name, "%s/dummy%d", testdir, i);
847                 ret = stat (name, &st);
848                 if (ret == -1) {
849                         RFS_ASSERT (errno == ENOENT);
850                         fd = open (name, O_CREAT|O_WRONLY);
851                         RFS_ASSERT (fd >=0);
852                         close (fd);
853                         return 0;
854                 };
855         }
856 }
857
858 int delete_one_dummy_file()
859 {
860         int i,ret;
861         static int index = 0;
862         static char name[1024];
863         struct stat st;
864
865         for (i=0; i<DUMMY_FILE_COUNT; i++) {
866                 index = (index+1) % DUMMY_FILE_COUNT;
867                 sprintf(name, "%s/dummy%d", testdir, i);
868                 ret = stat (name, &st);
869                 if (ret == 0) {
870                         ret = unlink (name);
871                         RFS_ASSERT (ret == 0);
872                         return;
873                 } else
874                         RFS_ASSERT (errno == ENOENT);
875         }
876         RFS_ASSERT (0);
877 }
878
879 int create_sub_holder_file(int holderno, int sub_holderno)
880 {
881         char name[256];
882         int fd, ret;
883         static char buf[MAX_DISK_FRAGMENT_SIZE];
884
885
886         RFS_ASSERT (MAX_DISK_FRAGMENT_SIZE >= DISK_FRAGMENT_SIZE);
887
888         sprintf(name, "%d.%d", holderno, sub_holderno);
889         printf ("create/write %s\n", name);
890         fd = open (name, O_CREAT|O_WRONLY);
891         RFS_ASSERT (fd >=0);
892         loop_write (fd, buf, DISK_FRAGMENT_SIZE);
893         close(fd);
894 }
895
896 int get_free_blocks ()
897 {
898         static struct statfs stfs;
899         int ret;
900
901         ret = statfs (testdir, &stfs);
902         RFS_ASSERT (ret == 0);
903         return (stfs.f_bfree);
904 }
905
906 int print_free_blocks (char *string)
907 {
908         static struct statfs stfs;
909         int ret;
910
911         ret = statfs (testdir, &stfs);
912         RFS_ASSERT (ret == 0);
913         printf("%s f_bfree %d \n", string, stfs.f_bfree);
914 }
915
916 int check_free_blocks (int num)
917 {
918         static struct statfs stfs;
919         int ret;
920
921         ret = statfs (testdir, &stfs);
922         RFS_ASSERT (ret == 0);
923         if (stfs.f_bfree!=num) {
924                 printf("f_bfree %d expected %d\n", stfs.f_bfree, num);
925                 RFS_ASSERT (0);
926         }
927 }
928
929 int progress_on_aged_file(int * num)
930 {
931         char buf[MAX_DISK_FRAGMENT_SIZE*MAX_HOLDER_SIZE];
932         static need_indirect_blocks = 0;
933         static skip_for_indirect_blocks = 0;
934         static int blkno = 0;
935
936         printf ("\n");
937         print_free_blocks("progress_on_aged_file begin");
938
939         if (skip_for_indirect_blocks == need_indirect_blocks) {
940                 //check_free_blocks(free_block_num);
941                 //RFS_ASSERT (free_block_num >= (1+need_indirect_blocks));
942                 (*num) --;
943                 printf("append to aged file %d bytes\n", DISK_FRAGMENT_SIZE);
944                 append_file (0, agename, DISK_FRAGMENT_SIZE);
945                 //*free_block_num -= (need_indirect_blocks +1)
946                 //check_free_blocks(free_block_num);
947
948                 blkno ++;
949                 if (((blkno - 12) % INDIRECT_FANOUT) == 0) {
950                         if (((blkno - (INDIRECT_FANOUT+12)) % (INDIRECT_FANOUT*INDIRECT_FANOUT)) == 0) {
951                                 if (blkno == 12 + INDIRECT_FANOUT + INDIRECT_FANOUT*INDIRECT_FANOUT) {
952                                         printf ("need_indirect_blocks is set to 3 blkno %d\n", blkno);
953                                         need_indirect_blocks = 3;
954                                 } else {
955                                         printf ("need_indirect_blocks is set to 2 blkno %d\n", blkno);
956                                         need_indirect_blocks = 2;
957                                 }
958                         } else {
959                                 printf ("need_indirect_blocks is set to 1 blkno %d\n", blkno);
960                                 need_indirect_blocks = 1;
961                         };
962                 } else {
963                         need_indirect_blocks = 0;
964                 }
965                 skip_for_indirect_blocks = 0;  
966         } else {
967                 skip_for_indirect_blocks ++;  
968         }
969
970         printf ("skip_for_indirect_blocks -- %d\n", skip_for_indirect_blocks);
971         print_free_blocks("progress_on_aged_file end");
972 }
973
974 int free_blocks (char * agename, int start, int num)
975 {
976         int holderno;
977         char name [128];
978         int ret;
979         struct stat st;
980         int sub_holderno;
981         int i;
982
983         printf ("free_blocks start %d  num %d\n", start, num);
984
985 BEGIN:
986         check_free_blocks(0);
987         if (num == 0)
988                 return start;
989         holderno = start/HOLDER_SIZE;
990         sub_holderno = start%HOLDER_SIZE;
991
992         sprintf (name, "%d", holderno);
993         
994         ret = stat (name, &st);
995         if (ret == -1) {
996                 RFS_ASSERT (errno == ENOENT);
997                 for (i=sub_holderno; (i<HOLDER_SIZE && num>0); i++) {
998                         sprintf(name, "%d.%d", holderno, i);
999                         ret = stat (name, &st);
1000                         if (ret == 0) {
1001
1002                                 printf ("sub_holder file %s is unlinked\n", name);
1003                                 ret = unlink(name);
1004                                 RFS_ASSERT (ret == 0);
1005
1006                                 create_one_dummy_file();
1007
1008                                 printf ("write to age file %d bytes\n", DISK_FRAGMENT_SIZE);
1009
1010                                 progress_on_aged_file(&num);
1011
1012                         } else { 
1013                                 printf ("sub_holder file %s is already used\n", name);
1014                                 RFS_ASSERT ((ret == -1) && (errno ==ENOENT));
1015                         }
1016                         start ++;
1017                 }
1018                 goto BEGIN; 
1019         }
1020         
1021         RFS_ASSERT (ret == 0);
1022         RFS_ASSERT (st.st_size == HOLDER_SIZE * DISK_FRAGMENT_SIZE);
1023         printf ("holder file %s is unlinked\n", name);
1024         ret = unlink(name);
1025         RFS_ASSERT (ret == 0);
1026         check_free_blocks(HOLDER_SIZE);
1027
1028         /* create the sub holders before the first slot that we need */
1029         for (i=0; i<sub_holderno; i++) {
1030                 delete_one_dummy_file();
1031                 create_sub_holder_file (holderno, i);
1032         }
1033
1034         /*
1035         i = (HOLDER_SIZE - sub_holderno) < num? (HOLDER_SIZE - sub_holderno): num;
1036         sub_holderno += i;
1037         start += i;
1038         num -= i;
1039         check_free_blocks (i);
1040         ret = loop_write (agefd, buf, DISK_FRAGMENT_SIZE*i);
1041         RFS_ASSERT (ret != -1);
1042         */
1043         i = HOLDER_SIZE - sub_holderno;
1044         check_free_blocks(i);
1045
1046         while ((sub_holderno < HOLDER_SIZE) && (num>0)) {
1047                 sub_holderno ++;
1048                 start ++;
1049
1050                 progress_on_aged_file(&num);
1051                                                 
1052                 RFS_ASSERT (ret != -1);
1053         }
1054
1055         /* create the sub holders after the slot that we need */
1056         for (i=sub_holderno; i<HOLDER_SIZE; i++) {
1057                 delete_one_dummy_file();
1058                 create_sub_holder_file (holderno, i);
1059         }
1060
1061         create_one_dummy_file();
1062         goto BEGIN;
1063 }
1064
1065 int main3(int argc, char ** argv)
1066 {
1067
1068         int block_anchor;
1069         int i;
1070         int agefd;
1071         char * buf;
1072         char cwd[1024];
1073         char * ret;
1074         struct stat st;
1075
1076         if (argc!=11) {
1077                 print_usage();
1078                 return;
1079         }
1080         i = 2;
1081
1082         CHUNK_SIZE = atoi(argv[i++]);
1083         CHUNK_DISTANCE = atoi (argv[i++]);
1084         CHUNK_NUM = atoi (argv[i++]);
1085         START_BNO = atoi (argv[i++]);
1086         HOLDER_SIZE = atoi (argv[i++]);
1087         RFS_ASSERT (HOLDER_SIZE <= MAX_HOLDER_SIZE);
1088         HOLDER_NUM = atoi (argv[i++]);
1089         DISK_FRAGMENT_SIZE = atoi (argv[i++]);
1090         RFS_ASSERT (DISK_FRAGMENT_SIZE <= MAX_DISK_FRAGMENT_SIZE);
1091         INDIRECT_FANOUT = (DISK_FRAGMENT_SIZE/sizeof(int));
1092         strcpy (testdir, argv[i++]);
1093         strcpy (agename, testdir);
1094         strcat (agename, argv[i++]);
1095         ret = stat (agename, &st);
1096         if (ret!=-1) {
1097                 printf ("%s already exists\n", agename);
1098         }       
1099         RFS_ASSERT (errno == ENOENT);
1100
1101         fprintf(fplog, "main3: to age one file %s in a customized way, CHUNK_SIZE %d CHUNK_DISTANCE %d CHUNK_NUM %d START_BNO %d HOLDER_SIZE %d HOLDER_NUM %d DISK_FRAGMENT_SIZE %d MAX_DISK_FRAGMENT_SIZE %d testdir %s\n", agename, CHUNK_SIZE, CHUNK_DISTANCE, CHUNK_NUM, START_BNO, HOLDER_SIZE, HOLDER_NUM, DISK_FRAGMENT_SIZE, MAX_DISK_FRAGMENT_SIZE, testdir);
1102         fflush(fplog);
1103
1104         /* change working directory */
1105         ret = getcwd(cwd, sizeof(cwd));
1106         RFS_ASSERT (ret == cwd);
1107         i = chdir (testdir);
1108         RFS_ASSERT (i==0);
1109
1110         if (START_BNO == -1) {
1111                 block_anchor = random() % (HOLDER_NUM*HOLDER_SIZE);
1112         } else {
1113                 RFS_ASSERT (START_BNO >=0);
1114                 block_anchor = START_BNO % (HOLDER_NUM*HOLDER_SIZE);
1115         }
1116         while (get_free_blocks()!=0) {
1117                 print_free_blocks("fill up initial file system blocks using space occupier");
1118                 append_file (0, "/b6/space_occupier", DISK_FRAGMENT_SIZE);
1119         };
1120         delete_one_dummy_file();
1121         agefd = open (agename, O_CREAT|O_WRONLY);
1122         RFS_ASSERT (agefd>=0);
1123         close (agefd);
1124
1125         buf = (char *)malloc (CHUNK_SIZE*DISK_FRAGMENT_SIZE);
1126         RFS_ASSERT (buf);
1127
1128         for (i=0; i<CHUNK_NUM; i++) {
1129                 block_anchor = (block_anchor + CHUNK_DISTANCE) % (HOLDER_NUM * HOLDER_SIZE);    
1130                 block_anchor = free_blocks (agename, block_anchor, CHUNK_SIZE);
1131         }
1132
1133         check_free_blocks(0);
1134         i = chdir (cwd);
1135         RFS_ASSERT (i==0);
1136 }
1137
1138 int main2(int argc, char ** argv)
1139 {
1140         int i, j;
1141         int size[3], num;
1142         FILE * fp[3];
1143         char name[3][128];
1144         char cmd[1024];
1145
1146         if (argc <= 4) {
1147                 print_usage();
1148                 return;
1149         }
1150         num = atoi(argv[argc-2]);
1151         strcpy (testdir, argv[argc-1]);
1152         fprintf(fplog, "main2: generate interleaved files\n");
1153     fprintf(fplog, "testdir %s number of files %d ", testdir, num);
1154         for (i=0; i<argc-4; i++) {
1155                 size[i] = atoi(argv[i+2]);
1156                 fprintf(fplog, "size[%d] %d ", i, size[i]);
1157
1158                 RFS_ASSERT (size[i] >=0 && size[i] < 1000000000);
1159                 strcpy (name[i], testdir);
1160                 sprintf (name[i], "%s/file%d", testdir, i);
1161                 sprintf(cmd, "touch %s", name[i]);
1162                 system(cmd);
1163                 printf ("write %s \n", name[i]);
1164         };
1165         fprintf(fplog, "\n");
1166         fflush(fplog);
1167
1168         for (j=0; j<num; j++) {
1169                 for (i=0; i<argc-4; i++)
1170                         append_file (i, name[i], size[i]);
1171         }
1172 }
1173
1174 int main(int argc, char ** argv)
1175 {
1176         int i;
1177         char cmd[1024];
1178         char AGELOG_NAME[1024]= "/home/ningning/agefs.log";
1179
1180         sprintf(cmd, "date >> %s", AGELOG_NAME);
1181         system (cmd);
1182         fplog = fopen(AGELOG_NAME, "a");
1183         RFS_ASSERT (fplog);
1184         for (i=0; i<argc; i++) {
1185                 fprintf(fplog, "%s ", argv[i]);
1186         }
1187         fprintf (fplog, "\n");
1188
1189         if (argc>1 && (!strcmp(argv[1], "fmt2"))) 
1190                 main2 (argc, argv);
1191         else if (argc>1 && (!strcmp(argv[1], "fmt3"))) 
1192                 main3 (argc, argv);
1193         else if (argc>1 && (!strcmp(argv[1], "fmt4"))) 
1194                 main4 (argc, argv);
1195         else 
1196                 main1 (argc, argv);
1197 END:
1198         fclose (fplog);
1199         sprintf(cmd, "date >> %s", AGELOG_NAME);
1200         system (cmd);
1201 }
1202
1203 int main1(int argc, char ** argv)
1204 {
1205         char * buf;
1206         static int disk_index=0;
1207         int nfs3proc, size, off, count;
1208         char procname[16];
1209         struct stat st;
1210         int ret;
1211         int i,j,k;
1212         int ftype_flag = 0, active_flag = 0;
1213         char name[MAX_PLAY_PATH_SIZE];  
1214         int sfh, psfh;
1215         char mapname[1024];
1216
1217         profile_t create_profile, write_profile;
1218         if (argc!=9) {
1219                 print_usage();
1220                 return;
1221         }
1222
1223         init();
1224         EVEN_CHUNK_SIZE = atoi(argv[1]);
1225         RFS_ASSERT ((EVEN_CHUNK_SIZE==0) || (EVEN_CHUNK_SIZE==1));
1226         FILE_RATIO = atoi (argv[2]);
1227         ACTIVE_RATIO = atoi(argv[3]);
1228         WRITE_CHUNK_NUM = atoi(argv[4]);
1229         MAX_FS_SIZE_MB = atoi(argv[5]);
1230
1231         if (WRITE_CHUNK_NUM==0)
1232                 MIN_WRITE_SIZE = 2000000000;
1233         else {
1234                 //MIN_WRITE_SIZE = DISK_FRAGMENT_SIZE;
1235                 MIN_WRITE_SIZE = 1;
1236         }
1237
1238         STAGE_NUM = atoi (argv[6]);
1239         strcpy (mapname, argv[7]);
1240         strcpy (testdir, argv[8]);
1241         ret = stat (testdir, &st);
1242         if ((ret == -1) && (errno==ENOENT)) {
1243                 ret = mkdir (testdir, S_IRWXU);
1244         }
1245         RFS_ASSERT (ret >= 0);
1246
1247         
1248         /* add testdir to obj_fh */
1249         add_fh_t (&obj_fh, testdir, 1, -1, -1, IS_DIR, EXIST, ACTIVE);
1250         exist_active_obj_num ++;
1251         if (ACTIVE_RATIO >0) 
1252                 read_fh_map (mapname);
1253
1254         print_fh_map(&obj_fh);
1255         init_profile_variables();
1256
1257         fprintf(fplog, "main1: populate the file system with both trace files and randomly generated files\n");
1258         fprintf(fplog, "EVEN_CHUNK_SIZE %d FILE_RATIO %d ACTIVE_RATIO %d WRITE_CHUNK_NUM %d MAX_FS_SIZE_MB %d STAGE_NUM %d fh_map %s testdir %s\n", EVEN_CHUNK_SIZE, FILE_RATIO, ACTIVE_RATIO, WRITE_CHUNK_NUM, MAX_FS_SIZE_MB, STAGE_NUM, mapname, testdir);
1259         system("date");
1260         printf("EVEN_CHUNK_SIZE %d FILE_RATIO %d ACTIVE_RATIO %d WRITE_CHUNK_NUM %d MAX_FS_SIZE_MB %d STAGE_NUM %d fh_map %s testdir %s\n", EVEN_CHUNK_SIZE, FILE_RATIO, ACTIVE_RATIO, WRITE_CHUNK_NUM, MAX_FS_SIZE_MB, STAGE_NUM, mapname, testdir);
1261         fflush(fplog);
1262
1263         profile_fp = fplog;
1264         init_profile ("create_profile", &create_profile);
1265         init_profile ("write_profile", &write_profile);
1266
1267         start_profile (&create_profile);
1268         printf ("start creat/mkdir, active_obj_num %d\n", active_obj_num);
1269         for (i=0; (exist_active_obj_num <= active_obj_num) && (fs_size_MB < MAX_FS_SIZE_MB); i++) {
1270
1271                 if ((i!=0) && ((i%10000)==0)) {
1272                         fprintf (stderr, "\n%d object created, exist_active_obj_num %d expected size %d MB\n", i, exist_active_obj_num, fs_size_MB);
1273                 }
1274
1275                 /* decide on the exact active obj or populated obj */
1276                 if (decide(ACTIVE_RATIO)) {
1277                         sfh = select_obj (&obj_fh, DONT_CARE, NON_EXIST, ACTIVE, 0, obj_fh.fh_max);
1278                         if (sfh == -1)
1279                                 break;
1280
1281                         obj_fh.fh[sfh].exist_flag = EXIST;
1282                         exist_active_obj_num ++;
1283                         ftype_flag = obj_fh.fh[sfh].ftype;
1284                         size = obj_fh.fh[sfh].size;
1285                 } else {
1286                         psfh = select_obj (&obj_fh, IS_DIR, EXIST, DONT_CARE, 0, obj_fh.fh_max);
1287                         strcpy (name, obj_fh.fh[psfh].path);
1288                         sfh = obj_fh.fh_max;
1289                         sprintf(name+strlen(name), "/AGE%d", obj_fh.fh_max); 
1290
1291                         /* decide next obj is file or directory */
1292                         if (decide(FILE_RATIO)) {
1293                                 ftype_flag = IS_FILE;
1294                                 size = get_file_size();
1295                         } else {
1296                                 ftype_flag = IS_DIR;
1297                                 size = -1;
1298                         }
1299                         add_fh_t (&obj_fh, name, sfh, psfh, size, ftype_flag, EXIST, INACTIVE);
1300
1301                 }
1302
1303                 /* make sure/create the  obj pathname on disk */
1304                 assure_exist (sfh, obj_fh.fh[sfh].path, ftype_flag);
1305                 /* write file to sizes according certain distribution 
1306                 if (ftype_flag == IS_FILE) 
1307                         append_file (obj_fh.fh[sfh].path, obj_fh.fh[sfh].size);
1308                 */
1309         }
1310         fprintf (stderr, "\n%d object created, exist_active_obj_num %d expected size %d MB\n", i, exist_active_obj_num, fs_size_MB);
1311
1312         end_profile (&create_profile);
1313         start_profile (&write_profile);
1314         //write_file_range (0, obj_fh.fh_max);
1315         for (i=1; i<=STAGE_NUM; i++) {
1316                 write_file_range (obj_fh.fh_max*(i-1)/STAGE_NUM, obj_fh.fh_max*i/STAGE_NUM);
1317                 //fprintf(stderr, "getchar\n");
1318                 //getchar();
1319         }
1320         end_profile (&write_profile);
1321
1322         print_profile ("create_profile", &create_profile);
1323         print_profile ("write_profile", &write_profile);
1324         printf ("exist_active_obj_num %d active_obj_num %d fs_size_MB %d\n",
1325                         exist_active_obj_num, active_obj_num, fs_size_MB);
1326
1327         print_fh_map(&obj_fh);
1328         print_result();
1329         printf ("end of file system initialization\n");
1330         system("date");
1331 }
1332
1333 int write_file_range (int min, int max)
1334 {
1335         int i, j, k, sfh;
1336         int write_size, disk_write_size;
1337
1338         i = 0, j=0, k=0;
1339         printf ("start writing files min %d max %d\n", min, max);
1340         while (1) {
1341                 sfh = select_obj (&obj_fh, IS_FILE, EXIST, DONT_CARE, min, max);
1342 /*
1343                 if (!decide(obj_fh.fh[sfh].size*100/(MIN_WRITE_SIZE*WRITE_CHUNK_NUM))) {
1344                         printf("skip writing small file\n");
1345                         continue;
1346                 }
1347 */
1348                 if (sfh == -1)
1349                         break;
1350                 write_size = get_write_size (obj_fh.fh[sfh].size, obj_fh.fh[sfh].cur_size);
1351                 obj_fh.fh[sfh].cur_size += write_size;
1352                 if (obj_fh.fh[sfh].cur_size == obj_fh.fh[sfh].size) {
1353                         obj_fh.fh[sfh].exist_flag = COMPLETE;
1354                 };
1355
1356 #define ACCUMULATE_SMALL_WRITE  
1357 // This option improves speed by 12 times.
1358 #ifdef ACCUMULATE_SMALL_WRITE
1359                 obj_fh.fh[sfh].accumulated_write_size += write_size;
1360                 if (obj_fh.fh[sfh].exist_flag == COMPLETE) {
1361                         disk_write_size = obj_fh.fh[sfh].accumulated_write_size;
1362                 } else {
1363                         disk_write_size = (obj_fh.fh[sfh].accumulated_write_size -
1364                                                           (obj_fh.fh[sfh].accumulated_write_size%DISK_FRAGMENT_SIZE));
1365                 };
1366                 obj_fh.fh[sfh].accumulated_write_size -= disk_write_size;
1367 #else
1368                 disk_write_size = write_size;
1369 #endif
1370
1371                 if (disk_write_size >0) {
1372                         append_file (sfh, obj_fh.fh[sfh].path, disk_write_size);
1373                         if ((i%1000)==0) {
1374                                 printf ("%d C ", i);
1375                                 fflush(stdout);
1376                                 k++;
1377                                 if ((k%10)==0)
1378                                         printf("\n");
1379                         }
1380                         i++;
1381                 } else {
1382                         if ((j%100000)==0) {
1383                                 printf ("%d c ", j);
1384                                 fflush(stdout);
1385                                 k++;
1386                                 if ((k%10)==0)
1387                                         printf("\n");
1388                         }
1389                         j++;
1390                 }
1391         }
1392 }
1393