]> git.pld-linux.org Git - packages/mysql.git/blob - innodb_overwrite_relay_log_info.patch
- make 'service mysql status' return LSB-compatible exit values
[packages/mysql.git] / innodb_overwrite_relay_log_info.patch
1 # name       : innodb_overwrite_relay_log_info.patch
2 # introduced : 11 or before
3 # maintainer : Yasufumi
4 #
5 #!!! notice !!!
6 # Any small change to this file in the main branch
7 # should be done or reviewed by the maintainer!
8 diff -ruN a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
9 --- a/storage/innobase/handler/ha_innodb.cc     2010-12-03 15:37:45.516105468 +0900
10 +++ b/storage/innobase/handler/ha_innodb.cc     2010-12-03 15:38:20.318952987 +0900
11 @@ -42,6 +42,8 @@
12  #pragma implementation                         // gcc: Class implementation
13  #endif
14  
15 +#define MYSQL_SERVER
16 +
17  #include <sql_table.h> // explain_filename, nz2, EXPLAIN_PARTITIONS_AS_COMMENT,
18                         // EXPLAIN_FILENAME_MAX_EXTRA_LENGTH
19  
20 @@ -53,6 +55,15 @@
21  #include <mysql/psi/psi.h>
22  #include <my_sys.h>
23  
24 +#ifdef MYSQL_SERVER
25 +#include <rpl_mi.h>
26 +#include <slave.h>
27 +// Defined in slave.cc
28 +int init_intvar_from_file(int* var, IO_CACHE* f, int default_val);
29 +int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
30 +                         const char *default_val);
31 +#endif /* MYSQL_SERVER */
32 +
33  /** @file ha_innodb.cc */
34  
35  /* Include necessary InnoDB headers */
36 @@ -91,6 +102,14 @@
37  #include "ha_innodb.h"
38  #include "i_s.h"
39  
40 +#ifdef MYSQL_SERVER
41 +// Defined in trx0sys.c
42 +extern char            trx_sys_mysql_master_log_name[];
43 +extern ib_int64_t      trx_sys_mysql_master_log_pos;
44 +extern char            trx_sys_mysql_relay_log_name[];
45 +extern ib_int64_t      trx_sys_mysql_relay_log_pos;
46 +#endif /* MYSQL_SERVER */
47 +
48  # ifndef MYSQL_PLUGIN_IMPORT
49  #  define MYSQL_PLUGIN_IMPORT /* nothing */
50  # endif /* MYSQL_PLUGIN_IMPORT */
51 @@ -163,6 +182,7 @@
52  static my_bool innobase_use_doublewrite                = TRUE;
53  static my_bool innobase_use_checksums                  = TRUE;
54  static my_bool innobase_locks_unsafe_for_binlog        = FALSE;
55 +static my_bool innobase_overwrite_relay_log_info       = FALSE;
56  static my_bool innobase_rollback_on_timeout            = FALSE;
57  static my_bool innobase_create_status_file             = FALSE;
58  static my_bool innobase_stats_on_metadata              = TRUE;
59 @@ -2248,6 +2268,89 @@
60         }
61  #endif /* DBUG_OFF */
62  
63 +#ifndef MYSQL_SERVER
64 +       innodb_overwrite_relay_log_info = FALSE;
65 +#endif
66 +
67 +#ifdef HAVE_REPLICATION
68 +#ifdef MYSQL_SERVER
69 +       /* read master log position from relay-log.info if exists */
70 +       char fname[FN_REFLEN+128];
71 +       int pos;
72 +       int info_fd;
73 +       IO_CACHE info_file;
74 +
75 +       fname[0] = '\0';
76 +
77 +       if(innobase_overwrite_relay_log_info) {
78 +
79 +       fprintf(stderr,
80 +               "InnoDB: Warning: innodb_overwrite_relay_log_info is enabled."
81 +               " Updates by other storage engines may not be synchronized.\n");
82 +
83 +       bzero((char*) &info_file, sizeof(info_file));
84 +       fn_format(fname, relay_log_info_file, mysql_data_home, "", 4+32);
85 +
86 +       int error=0;
87 +
88 +       if (!access(fname,F_OK)) {
89 +               /* exist */
90 +               if ((info_fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0) {
91 +                       error=1;
92 +               } else if (init_io_cache(&info_file, info_fd, IO_SIZE*2,
93 +                                       READ_CACHE, 0L, 0, MYF(MY_WME))) {
94 +                       error=1;
95 +               }
96 +
97 +               if (error) {
98 +relay_info_error:
99 +                       if (info_fd >= 0)
100 +                               my_close(info_fd, MYF(0));
101 +                       fname[0] = '\0';
102 +                       goto skip_relay;
103 +               }
104 +       } else {
105 +               fname[0] = '\0';
106 +               goto skip_relay;
107 +       }
108 +
109 +       if (init_strvar_from_file(fname, sizeof(fname), &info_file, "") || /* dummy (it is relay-log) */
110 +           init_intvar_from_file(&pos, &info_file, BIN_LOG_HEADER_SIZE)) { 
111 +               end_io_cache(&info_file);
112 +               error=1;
113 +               goto relay_info_error;
114 +       }
115 +
116 +       fprintf(stderr,
117 +               "InnoDB: relay-log.info is detected.\n"
118 +               "InnoDB: relay log: position %u, file name %s\n",
119 +               pos, fname);
120 +
121 +       strncpy(trx_sys_mysql_relay_log_name, fname, TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN);
122 +       trx_sys_mysql_relay_log_pos = (ib_int64_t) pos;
123 +
124 +       if (init_strvar_from_file(fname, sizeof(fname), &info_file, "") ||
125 +           init_intvar_from_file(&pos, &info_file, 0)) {
126 +               end_io_cache(&info_file);
127 +               error=1;
128 +               goto relay_info_error;
129 +       }
130 +
131 +       fprintf(stderr,
132 +               "InnoDB: master log: position %u, file name %s\n",
133 +               pos, fname);
134 +
135 +       strncpy(trx_sys_mysql_master_log_name, fname, TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN);
136 +       trx_sys_mysql_master_log_pos = (ib_int64_t) pos;
137 +
138 +       end_io_cache(&info_file);
139 +       if (info_fd >= 0)
140 +               my_close(info_fd, MYF(0));
141 +       }
142 +skip_relay:
143 +#endif /* MYSQL_SERVER */
144 +#endif /* HAVE_REPLICATION */
145 +
146         /* Check that values don't overflow on 32-bit systems. */
147         if (sizeof(ulint) == 4) {
148                 if (innobase_buffer_pool_size > UINT_MAX32) {
149 @@ -2546,6 +2649,76 @@
150                 goto mem_free_and_error;
151         }
152  
153 +#ifdef HAVE_REPLICATION
154 +#ifdef MYSQL_SERVER
155 +       if(innobase_overwrite_relay_log_info) {
156 +       /* If InnoDB progressed from relay-log.info, overwrite it */
157 +       if (fname[0] == '\0') {
158 +               fprintf(stderr,
159 +                       "InnoDB: Something is wrong with the file relay-info.log. InnoDB will not overwrite it.\n");
160 +       } else if (0 != strcmp(fname, trx_sys_mysql_master_log_name)
161 +                  || pos != trx_sys_mysql_master_log_pos) {
162 +               /* Overwrite relay-log.info */
163 +               bzero((char*) &info_file, sizeof(info_file));
164 +               fn_format(fname, relay_log_info_file, mysql_data_home, "", 4+32);
165 +
166 +               int error = 0;
167 +
168 +               if (!access(fname,F_OK)) {
169 +                       /* exist */
170 +                       if ((info_fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0) {
171 +                               error = 1;
172 +                       } else if (init_io_cache(&info_file, info_fd, IO_SIZE*2,
173 +                                               WRITE_CACHE, 0L, 0, MYF(MY_WME))) {
174 +                               error = 1;
175 +                       }
176 +
177 +                       if (error) {
178 +                               if (info_fd >= 0)
179 +                                       my_close(info_fd, MYF(0));
180 +                               goto skip_overwrite;
181 +                       }
182 +               } else {
183 +                       error = 1;
184 +                       goto skip_overwrite;
185 +               }
186 +
187 +               char buff[FN_REFLEN*2+22*2+4], *pos;
188 +
189 +               my_b_seek(&info_file, 0L);
190 +               pos=strmov(buff, trx_sys_mysql_relay_log_name);
191 +               *pos++='\n';
192 +               pos=longlong2str(trx_sys_mysql_relay_log_pos, pos, 10);
193 +               *pos++='\n';
194 +               pos=strmov(pos, trx_sys_mysql_master_log_name);
195 +               *pos++='\n';
196 +               pos=longlong2str(trx_sys_mysql_master_log_pos, pos, 10);
197 +               *pos='\n';
198 +
199 +               if (my_b_write(&info_file, (uchar*) buff, (size_t) (pos-buff)+1))
200 +                       error = 1;
201 +               if (flush_io_cache(&info_file))
202 +                       error = 1;
203 +
204 +               end_io_cache(&info_file);
205 +               if (info_fd >= 0)
206 +                       my_close(info_fd, MYF(0));
207 +skip_overwrite:
208 +               if (error) {
209 +                       fprintf(stderr,
210 +                               "InnoDB: ERROR: An error occurred while overwriting relay-log.info.\n");
211 +               } else {
212 +                       fprintf(stderr,
213 +                               "InnoDB: The file relay-log.info was successfully overwritten.\n");
214 +               }
215 +       } else {
216 +               fprintf(stderr,
217 +                       "InnoDB: InnoDB and relay-log.info are synchronized. InnoDB will not overwrite it.\n");
218 +       }
219 +       }
220 +#endif /* MYSQL_SERVER */
221 +#endif /* HAVE_REPLICATION */
222 +
223         innobase_old_blocks_pct = buf_LRU_old_ratio_update(
224                 innobase_old_blocks_pct, TRUE);
225  
226 @@ -2658,6 +2831,25 @@
227         trx_t*  trx)    /*!< in: transaction handle */
228  {
229         if (trx_is_started(trx)) {
230 +#ifdef HAVE_REPLICATION
231 +#ifdef MYSQL_SERVER
232 +               THD *thd=current_thd;
233 +
234 +               if (thd && thd->slave_thread) {
235 +                       /* Update the replication position info inside InnoDB */
236 +                       trx->mysql_master_log_file_name
237 +                               = active_mi->rli.group_master_log_name;
238 +                       trx->mysql_master_log_pos
239 +                               = ((ib_int64_t)active_mi->rli.group_master_log_pos +
240 +                                  ((ib_int64_t)active_mi->rli.future_event_relay_log_pos -
241 +                                   (ib_int64_t)active_mi->rli.group_relay_log_pos));
242 +                       trx->mysql_relay_log_file_name
243 +                               = active_mi->rli.group_relay_log_name;
244 +                       trx->mysql_relay_log_pos
245 +                               = (ib_int64_t)active_mi->rli.future_event_relay_log_pos;
246 +               }
247 +#endif /* MYSQL_SERVER */
248 +#endif /* HAVE_REPLICATION */
249  
250                 trx_commit_for_mysql(trx);
251         }
252 @@ -11014,6 +11206,12 @@
253    "The common part for InnoDB table spaces.",
254    NULL, NULL, NULL);
255  
256 +static MYSQL_SYSVAR_BOOL(recovery_update_relay_log, innobase_overwrite_relay_log_info,
257 +  PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
258 +  "During InnoDB crash recovery on slave overwrite relay-log.info "
259 +  "to align master log file position if information in InnoDB and relay-log.info is different.",
260 +  NULL, NULL, FALSE);
261 +
262  static MYSQL_SYSVAR_BOOL(doublewrite, innobase_use_doublewrite,
263    PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
264    "Enable InnoDB doublewrite buffer (enabled by default). "
265 @@ -11474,6 +11672,7 @@
266    MYSQL_SYSVAR(old_blocks_pct),
267    MYSQL_SYSVAR(old_blocks_time),
268    MYSQL_SYSVAR(open_files),
269 +  MYSQL_SYSVAR(recovery_update_relay_log),
270    MYSQL_SYSVAR(rollback_on_timeout),
271    MYSQL_SYSVAR(stats_on_metadata),
272    MYSQL_SYSVAR(stats_sample_pages),
273 diff -ruN a/storage/innobase/include/trx0sys.h b/storage/innobase/include/trx0sys.h
274 --- a/storage/innobase/include/trx0sys.h        2010-11-03 07:01:13.000000000 +0900
275 +++ b/storage/innobase/include/trx0sys.h        2010-12-03 15:38:20.321953297 +0900
276 @@ -53,6 +53,9 @@
277  extern ib_int64_t      trx_sys_mysql_master_log_pos;
278  /* @} */
279  
280 +extern char            trx_sys_mysql_relay_log_name[];
281 +extern ib_int64_t      trx_sys_mysql_relay_log_pos;
282 +
283  /** If this MySQL server uses binary logging, after InnoDB has been inited
284  and if it has done a crash recovery, we store the binlog file name and position
285  here. */
286 @@ -287,7 +290,8 @@
287  void
288  trx_sys_update_mysql_binlog_offset(
289  /*===============================*/
290 -       const char*     file_name,/*!< in: MySQL log file name */
291 +       trx_sysf_t*     sys_header,
292 +       const char*     file_name_in,/*!< in: MySQL log file name */
293         ib_int64_t      offset, /*!< in: position in that log file */
294         ulint           field,  /*!< in: offset of the MySQL log info field in
295                                 the trx sys header */
296 @@ -482,6 +486,7 @@
297  @see trx_sys_mysql_master_log_name
298  @see trx_sys_mysql_bin_log_name */
299  #define TRX_SYS_MYSQL_LOG_NAME_LEN     512
300 +#define TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN      480     /* (500 - 12) is dead line. */
301  /** Contents of TRX_SYS_MYSQL_LOG_MAGIC_N_FLD */
302  #define TRX_SYS_MYSQL_LOG_MAGIC_N      873422344
303  
304 @@ -491,6 +496,7 @@
305  /** The offset of the MySQL replication info in the trx system header;
306  this contains the same fields as TRX_SYS_MYSQL_LOG_INFO below */
307  #define TRX_SYS_MYSQL_MASTER_LOG_INFO  (UNIV_PAGE_SIZE - 2000)
308 +#define TRX_SYS_MYSQL_RELAY_LOG_INFO   (UNIV_PAGE_SIZE - 1500)
309  
310  /** The offset of the MySQL binlog offset info in the trx system header */
311  #define TRX_SYS_MYSQL_LOG_INFO         (UNIV_PAGE_SIZE - 1000)
312 diff -ruN a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h
313 --- a/storage/innobase/include/trx0trx.h        2010-12-03 15:18:48.894955550 +0900
314 +++ b/storage/innobase/include/trx0trx.h        2010-12-03 15:38:20.323953416 +0900
315 @@ -580,6 +580,20 @@
316         ib_int64_t      mysql_log_offset;/* if MySQL binlog is used, this field
317                                         contains the end offset of the binlog
318                                         entry */
319 +       const char*     mysql_master_log_file_name;
320 +                                       /* if the database server is a MySQL
321 +                                       replication slave, we have here the
322 +                                       master binlog name up to which
323 +                                       replication has processed; otherwise
324 +                                       this is a pointer to a null
325 +                                       character */
326 +       ib_int64_t      mysql_master_log_pos;
327 +                                       /* if the database server is a MySQL
328 +                                       replication slave, this is the
329 +                                       position in the log file up to which
330 +                                       replication has processed */
331 +       const char*     mysql_relay_log_file_name;
332 +       ib_int64_t      mysql_relay_log_pos;
333         /*------------------------------*/
334         ulint           n_mysql_tables_in_use; /* number of Innobase tables
335                                         used in the processing of the current
336 diff -ruN a/storage/innobase/trx/trx0sys.c b/storage/innobase/trx/trx0sys.c
337 --- a/storage/innobase/trx/trx0sys.c    2010-11-03 07:01:13.000000000 +0900
338 +++ b/storage/innobase/trx/trx0sys.c    2010-12-03 15:38:20.325956917 +0900
339 @@ -76,13 +76,16 @@
340  file name and position here. */
341  /* @{ */
342  /** Master binlog file name */
343 -UNIV_INTERN char       trx_sys_mysql_master_log_name[TRX_SYS_MYSQL_LOG_NAME_LEN];
344 +UNIV_INTERN char       trx_sys_mysql_master_log_name[TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN];
345  /** Master binlog file position.  We have successfully got the updates
346  up to this position.  -1 means that no crash recovery was needed, or
347  there was no master log position info inside InnoDB.*/
348  UNIV_INTERN ib_int64_t trx_sys_mysql_master_log_pos    = -1;
349  /* @} */
350  
351 +UNIV_INTERN char       trx_sys_mysql_relay_log_name[TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN];
352 +UNIV_INTERN ib_int64_t trx_sys_mysql_relay_log_pos     = -1;
353 +
354  /** If this MySQL server uses binary logging, after InnoDB has been inited
355  and if it has done a crash recovery, we store the binlog file name and position
356  here. */
357 @@ -684,23 +687,25 @@
358  void
359  trx_sys_update_mysql_binlog_offset(
360  /*===============================*/
361 -       const char*     file_name,/*!< in: MySQL log file name */
362 +       trx_sysf_t*     sys_header,
363 +       const char*     file_name_in,/*!< in: MySQL log file name */
364         ib_int64_t      offset, /*!< in: position in that log file */
365         ulint           field,  /*!< in: offset of the MySQL log info field in
366                                 the trx sys header */
367         mtr_t*          mtr)    /*!< in: mtr */
368  {
369 -       trx_sysf_t*     sys_header;
370 +       const char*     file_name;
371  
372 -       if (ut_strlen(file_name) >= TRX_SYS_MYSQL_LOG_NAME_LEN) {
373 +       if (ut_strlen(file_name_in) >= TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN) {
374  
375                 /* We cannot fit the name to the 512 bytes we have reserved */
376 +               /* -> To store relay log file information, file_name must fit to the 480 bytes */
377  
378 -               return;
379 +               file_name = "";
380 +       } else {
381 +               file_name = file_name_in;
382         }
383  
384 -       sys_header = trx_sysf_get(mtr);
385 -
386         if (mach_read_from_4(sys_header + field
387                              + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD)
388             != TRX_SYS_MYSQL_LOG_MAGIC_N) {
389 @@ -822,13 +827,26 @@
390                                          + TRX_SYS_MYSQL_LOG_OFFSET_LOW),
391                 sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
392                 + TRX_SYS_MYSQL_LOG_NAME);
393 +
394 +       fprintf(stderr,
395 +               "InnoDB: and relay log file\n"
396 +               "InnoDB: position %lu %lu, file name %s\n",
397 +               (ulong) mach_read_from_4(sys_header
398 +                                        + TRX_SYS_MYSQL_RELAY_LOG_INFO
399 +                                        + TRX_SYS_MYSQL_LOG_OFFSET_HIGH),
400 +               (ulong) mach_read_from_4(sys_header
401 +                                        + TRX_SYS_MYSQL_RELAY_LOG_INFO
402 +                                        + TRX_SYS_MYSQL_LOG_OFFSET_LOW),
403 +               sys_header + TRX_SYS_MYSQL_RELAY_LOG_INFO
404 +               + TRX_SYS_MYSQL_LOG_NAME);
405 +
406         /* Copy the master log position info to global variables we can
407         use in ha_innobase.cc to initialize glob_mi to right values */
408  
409         ut_memcpy(trx_sys_mysql_master_log_name,
410                   sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
411                   + TRX_SYS_MYSQL_LOG_NAME,
412 -                 TRX_SYS_MYSQL_LOG_NAME_LEN);
413 +                 TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN);
414  
415         trx_sys_mysql_master_log_pos
416                 = (((ib_int64_t) mach_read_from_4(
417 @@ -837,6 +855,19 @@
418                 + ((ib_int64_t) mach_read_from_4(
419                            sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
420                            + TRX_SYS_MYSQL_LOG_OFFSET_LOW));
421 +
422 +       ut_memcpy(trx_sys_mysql_relay_log_name,
423 +                 sys_header + TRX_SYS_MYSQL_RELAY_LOG_INFO
424 +                 + TRX_SYS_MYSQL_LOG_NAME,
425 +                 TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN);
426 +
427 +       trx_sys_mysql_relay_log_pos
428 +               = (((ib_int64_t) mach_read_from_4(
429 +                           sys_header + TRX_SYS_MYSQL_RELAY_LOG_INFO
430 +                           + TRX_SYS_MYSQL_LOG_OFFSET_HIGH)) << 32)
431 +               + ((ib_int64_t) mach_read_from_4(
432 +                          sys_header + TRX_SYS_MYSQL_RELAY_LOG_INFO
433 +                          + TRX_SYS_MYSQL_LOG_OFFSET_LOW));
434         mtr_commit(&mtr);
435  }
436  
437 diff -ruN a/storage/innobase/trx/trx0trx.c b/storage/innobase/trx/trx0trx.c
438 --- a/storage/innobase/trx/trx0trx.c    2010-12-03 15:37:45.549028990 +0900
439 +++ b/storage/innobase/trx/trx0trx.c    2010-12-03 15:38:20.328957217 +0900
440 @@ -138,6 +138,10 @@
441  
442         trx->mysql_log_file_name = NULL;
443         trx->mysql_log_offset = 0;
444 +       trx->mysql_master_log_file_name = "";
445 +       trx->mysql_master_log_pos = 0;
446 +       trx->mysql_relay_log_file_name = "";
447 +       trx->mysql_relay_log_pos = 0;
448  
449         mutex_create(trx_undo_mutex_key, &trx->undo_mutex, SYNC_TRX_UNDO);
450  
451 @@ -820,6 +824,7 @@
452  {
453         mtr_t           mtr;
454         trx_rseg_t*     rseg;
455 +       trx_sysf_t*     sys_header = NULL;
456  
457         ut_ad(!mutex_own(&kernel_mutex));
458  
459 @@ -873,8 +878,12 @@
460  
461         if (trx->mysql_log_file_name
462             && trx->mysql_log_file_name[0] != '\0') {
463 +               if (!sys_header) {
464 +                       sys_header = trx_sysf_get(&mtr);
465 +               }
466  
467                 trx_sys_update_mysql_binlog_offset(
468 +                       sys_header,
469                         trx->mysql_log_file_name,
470                         trx->mysql_log_offset,
471                         TRX_SYS_MYSQL_LOG_INFO, &mtr);
472 @@ -882,6 +891,27 @@
473                 trx->mysql_log_file_name = NULL;
474         }
475  
476 +       if (trx->mysql_master_log_file_name[0] != '\0') {
477 +               /* This database server is a MySQL replication slave */
478 +               if (!sys_header) {
479 +                       sys_header = trx_sysf_get(&mtr);
480 +               }
481 +
482 +               trx_sys_update_mysql_binlog_offset(
483 +                       sys_header,
484 +                       trx->mysql_relay_log_file_name,
485 +                       trx->mysql_relay_log_pos,
486 +                       TRX_SYS_MYSQL_RELAY_LOG_INFO, &mtr);
487 +
488 +               trx_sys_update_mysql_binlog_offset(
489 +                       sys_header,
490 +                       trx->mysql_master_log_file_name,
491 +                       trx->mysql_master_log_pos,
492 +                       TRX_SYS_MYSQL_MASTER_LOG_INFO, &mtr);
493 +
494 +               trx->mysql_master_log_file_name = "";
495 +       }
496 +
497         /* The following call commits the mini-transaction, making the
498         whole transaction committed in the file-based world, at this
499         log sequence number. The transaction becomes 'durable' when
This page took 0.066509 seconds and 3 git commands to generate.