~drizzle-trunk/drizzle/development

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
diff -aur tar-1.19/src/common.h tar-1.19-patched/src/common.h
--- tar-1.19/src/common.h	2007-09-26 17:42:25.000000000 -0400
+++ tar-1.19-patched/src/common.h	2008-04-05 19:21:21.000000000 -0400
@@ -270,6 +270,8 @@
 /* Specified maximum byte length of each tape volume (multiple of 1024).  */
 GLOBAL tarlong tape_length_option;
 
+GLOBAL unsigned long long read_rate_option;
+
 GLOBAL bool to_stdout_option;
 
 GLOBAL bool totals_option;
diff -aur tar-1.19/src/tar.c tar-1.19-patched/src/tar.c
--- tar-1.19/src/tar.c	2007-09-26 17:36:58.000000000 -0400
+++ tar-1.19-patched/src/tar.c	2008-04-05 19:23:28.000000000 -0400
@@ -271,6 +271,7 @@
   MODE_OPTION,
   MTIME_OPTION,
   NEWER_MTIME_OPTION,
+  READ_RATE_OPTION,
   NO_ANCHORED_OPTION,
   NO_DELAY_DIRECTORY_RESTORE_OPTION,
   NO_IGNORE_CASE_OPTION,
@@ -408,6 +409,10 @@
       " NUMBER defaults to 1"), GRID+1 },
   {"seek", 'n', NULL, 0,
    N_("archive is seekable"), GRID+1 },
+
+  {"read-rate", READ_RATE_OPTION, N_("RATE"), 0,
+    N_("throttle read i/o speed down to RATE bytes/sec"), GRID+1 },
+
 #undef GRID
 
 #define GRID 30
@@ -1373,6 +1378,14 @@
 			  : "--after-date", arg, &newer_mtime_option);
       break;
 
+    case READ_RATE_OPTION:
+      if (read_rate_option > 0)
+  	  USAGE_ERROR ((0, 0, _("More than one throttling option")));
+      read_rate_option = strtoull(arg, 0, 10);
+      if (read_rate_option < 0)
+  	  USAGE_ERROR ((0, 0, _("Too small read rate value")));
+      break;
+
     case 'o':
       args->o_option = true;
       break;
diff -aur tar-1.19/src/create.c tar-1.19-patched/src/create.c
--- tar-1.19/src/create.c	2007-10-05 13:46:49.000000000 -0400
+++ tar-1.19-patched/src/create.c	2008-04-06 02:54:33.000000000 -0400
@@ -1019,12 +1019,54 @@
     }
 }
 
+static void
+throttle_io(off_t *transferred_bytes) {
+  static unsigned long long last_usec;
+  unsigned long long usec;
+  long long int delay;
+  struct timezone tz;
+  struct timeval tv;
+  float desired_rate = read_rate_option / 1000000.0; /* 1Mbytes /s = 1 byte/microsecond */
+
+  /* Do not perform throttling if not asked to */
+  if (read_rate_option == 0) return;
+
+  /* Get current time in microseconds */
+  gettimeofday(&tv, &tz);
+  usec = (unsigned long long)tv.tv_sec * 1000000L + tv.tv_usec;
+
+  /* Just init our time counter */
+  if (transferred_bytes == 0) {
+    last_usec = usec;
+    return;
+  }
+  
+  /* Calculate delay for throttling (in microseconds) */
+  delay = ((float)*transferred_bytes / desired_rate) - (usec - last_usec);
+
+  /* Skip throttling if delay is not needed */
+  if (delay < 100000 || delay > 10000000L) return;
+  
+  /* Perform delay for throttling */
+  usleep((useconds_t) delay);
+  *transferred_bytes = 0;
+  
+  /* Save time for next round */
+  gettimeofday(&tv, &tz);
+  last_usec = (unsigned long long)tv.tv_sec * 1000000L + tv.tv_usec;
+}
+
 static enum dump_status
 dump_regular_file (int fd, struct tar_stat_info *st)
 {
   off_t size_left = st->stat.st_size;
   off_t block_ordinal;
   union block *blk;
+  off_t transferred_bytes = 0;
+
+  /* ----Init throttle timer ---*/
+  throttle_io(0);
+  /*---------------------------*/
 
   block_ordinal = current_block_ordinal ();
   blk = start_header (st);
@@ -1068,6 +1110,11 @@
       size_left -= count;
       set_next_block_after (blk + (bufsize - 1) / BLOCKSIZE);
 
+      /* ------ I/O trottling ------*/
+      transferred_bytes += count;
+      throttle_io(&transferred_bytes);
+      /*---------------------------*/
+
       if (count != bufsize)
 	{
 	  char buf[UINTMAX_STRSIZE_BOUND];