Merge branch 'sg/complete-configuration-variables'
[git] / builtin / gc.c
1 /*
2  * git gc builtin command
3  *
4  * Cleanup unreachable files and optimize the repository.
5  *
6  * Copyright (c) 2007 James Bowes
7  *
8  * Based on git-gc.sh, which is
9  *
10  * Copyright (c) 2006 Shawn O. Pearce
11  */
12
13 #include "builtin.h"
14 #include "repository.h"
15 #include "config.h"
16 #include "tempfile.h"
17 #include "lockfile.h"
18 #include "parse-options.h"
19 #include "run-command.h"
20 #include "sigchain.h"
21 #include "argv-array.h"
22 #include "commit.h"
23 #include "commit-graph.h"
24 #include "packfile.h"
25 #include "object-store.h"
26 #include "pack.h"
27 #include "pack-objects.h"
28 #include "blob.h"
29 #include "tree.h"
30
31 #define FAILED_RUN "failed to run %s"
32
33 static const char * const builtin_gc_usage[] = {
34         N_("git gc [<options>]"),
35         NULL
36 };
37
38 static int pack_refs = 1;
39 static int prune_reflogs = 1;
40 static int aggressive_depth = 50;
41 static int aggressive_window = 250;
42 static int gc_auto_threshold = 6700;
43 static int gc_auto_pack_limit = 50;
44 static int detach_auto = 1;
45 static timestamp_t gc_log_expire_time;
46 static const char *gc_log_expire = "1.day.ago";
47 static const char *prune_expire = "2.weeks.ago";
48 static const char *prune_worktrees_expire = "3.months.ago";
49 static unsigned long big_pack_threshold;
50 static unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;
51
52 static struct argv_array pack_refs_cmd = ARGV_ARRAY_INIT;
53 static struct argv_array reflog = ARGV_ARRAY_INIT;
54 static struct argv_array repack = ARGV_ARRAY_INIT;
55 static struct argv_array prune = ARGV_ARRAY_INIT;
56 static struct argv_array prune_worktrees = ARGV_ARRAY_INIT;
57 static struct argv_array rerere = ARGV_ARRAY_INIT;
58
59 static struct tempfile *pidfile;
60 static struct lock_file log_lock;
61
62 static struct string_list pack_garbage = STRING_LIST_INIT_DUP;
63
64 static void clean_pack_garbage(void)
65 {
66         int i;
67         for (i = 0; i < pack_garbage.nr; i++)
68                 unlink_or_warn(pack_garbage.items[i].string);
69         string_list_clear(&pack_garbage, 0);
70 }
71
72 static void report_pack_garbage(unsigned seen_bits, const char *path)
73 {
74         if (seen_bits == PACKDIR_FILE_IDX)
75                 string_list_append(&pack_garbage, path);
76 }
77
78 static void process_log_file(void)
79 {
80         struct stat st;
81         if (fstat(get_lock_file_fd(&log_lock), &st)) {
82                 /*
83                  * Perhaps there was an i/o error or another
84                  * unlikely situation.  Try to make a note of
85                  * this in gc.log along with any existing
86                  * messages.
87                  */
88                 int saved_errno = errno;
89                 fprintf(stderr, _("Failed to fstat %s: %s"),
90                         get_tempfile_path(log_lock.tempfile),
91                         strerror(saved_errno));
92                 fflush(stderr);
93                 commit_lock_file(&log_lock);
94                 errno = saved_errno;
95         } else if (st.st_size) {
96                 /* There was some error recorded in the lock file */
97                 commit_lock_file(&log_lock);
98         } else {
99                 /* No error, clean up any old gc.log */
100                 unlink(git_path("gc.log"));
101                 rollback_lock_file(&log_lock);
102         }
103 }
104
105 static void process_log_file_at_exit(void)
106 {
107         fflush(stderr);
108         process_log_file();
109 }
110
111 static void process_log_file_on_signal(int signo)
112 {
113         process_log_file();
114         sigchain_pop(signo);
115         raise(signo);
116 }
117
118 static int gc_config_is_timestamp_never(const char *var)
119 {
120         const char *value;
121         timestamp_t expire;
122
123         if (!git_config_get_value(var, &value) && value) {
124                 if (parse_expiry_date(value, &expire))
125                         die(_("failed to parse '%s' value '%s'"), var, value);
126                 return expire == 0;
127         }
128         return 0;
129 }
130
131 static void gc_config(void)
132 {
133         const char *value;
134
135         if (!git_config_get_value("gc.packrefs", &value)) {
136                 if (value && !strcmp(value, "notbare"))
137                         pack_refs = -1;
138                 else
139                         pack_refs = git_config_bool("gc.packrefs", value);
140         }
141
142         if (gc_config_is_timestamp_never("gc.reflogexpire") &&
143             gc_config_is_timestamp_never("gc.reflogexpireunreachable"))
144                 prune_reflogs = 0;
145
146         git_config_get_int("gc.aggressivewindow", &aggressive_window);
147         git_config_get_int("gc.aggressivedepth", &aggressive_depth);
148         git_config_get_int("gc.auto", &gc_auto_threshold);
149         git_config_get_int("gc.autopacklimit", &gc_auto_pack_limit);
150         git_config_get_bool("gc.autodetach", &detach_auto);
151         git_config_get_expiry("gc.pruneexpire", &prune_expire);
152         git_config_get_expiry("gc.worktreepruneexpire", &prune_worktrees_expire);
153         git_config_get_expiry("gc.logexpiry", &gc_log_expire);
154
155         git_config_get_ulong("gc.bigpackthreshold", &big_pack_threshold);
156         git_config_get_ulong("pack.deltacachesize", &max_delta_cache_size);
157
158         git_config(git_default_config, NULL);
159 }
160
161 static int too_many_loose_objects(void)
162 {
163         /*
164          * Quickly check if a "gc" is needed, by estimating how
165          * many loose objects there are.  Because SHA-1 is evenly
166          * distributed, we can check only one and get a reasonable
167          * estimate.
168          */
169         DIR *dir;
170         struct dirent *ent;
171         int auto_threshold;
172         int num_loose = 0;
173         int needed = 0;
174         const unsigned hexsz_loose = the_hash_algo->hexsz - 2;
175
176         dir = opendir(git_path("objects/17"));
177         if (!dir)
178                 return 0;
179
180         auto_threshold = DIV_ROUND_UP(gc_auto_threshold, 256);
181         while ((ent = readdir(dir)) != NULL) {
182                 if (strspn(ent->d_name, "0123456789abcdef") != hexsz_loose ||
183                     ent->d_name[hexsz_loose] != '\0')
184                         continue;
185                 if (++num_loose > auto_threshold) {
186                         needed = 1;
187                         break;
188                 }
189         }
190         closedir(dir);
191         return needed;
192 }
193
194 static struct packed_git *find_base_packs(struct string_list *packs,
195                                           unsigned long limit)
196 {
197         struct packed_git *p, *base = NULL;
198
199         for (p = get_all_packs(the_repository); p; p = p->next) {
200                 if (!p->pack_local)
201                         continue;
202                 if (limit) {
203                         if (p->pack_size >= limit)
204                                 string_list_append(packs, p->pack_name);
205                 } else if (!base || base->pack_size < p->pack_size) {
206                         base = p;
207                 }
208         }
209
210         if (base)
211                 string_list_append(packs, base->pack_name);
212
213         return base;
214 }
215
216 static int too_many_packs(void)
217 {
218         struct packed_git *p;
219         int cnt;
220
221         if (gc_auto_pack_limit <= 0)
222                 return 0;
223
224         for (cnt = 0, p = get_all_packs(the_repository); p; p = p->next) {
225                 if (!p->pack_local)
226                         continue;
227                 if (p->pack_keep)
228                         continue;
229                 /*
230                  * Perhaps check the size of the pack and count only
231                  * very small ones here?
232                  */
233                 cnt++;
234         }
235         return gc_auto_pack_limit < cnt;
236 }
237
238 static uint64_t total_ram(void)
239 {
240 #if defined(HAVE_SYSINFO)
241         struct sysinfo si;
242
243         if (!sysinfo(&si))
244                 return si.totalram;
245 #elif defined(HAVE_BSD_SYSCTL) && (defined(HW_MEMSIZE) || defined(HW_PHYSMEM))
246         int64_t physical_memory;
247         int mib[2];
248         size_t length;
249
250         mib[0] = CTL_HW;
251 # if defined(HW_MEMSIZE)
252         mib[1] = HW_MEMSIZE;
253 # else
254         mib[1] = HW_PHYSMEM;
255 # endif
256         length = sizeof(int64_t);
257         if (!sysctl(mib, 2, &physical_memory, &length, NULL, 0))
258                 return physical_memory;
259 #elif defined(GIT_WINDOWS_NATIVE)
260         MEMORYSTATUSEX memInfo;
261
262         memInfo.dwLength = sizeof(MEMORYSTATUSEX);
263         if (GlobalMemoryStatusEx(&memInfo))
264                 return memInfo.ullTotalPhys;
265 #endif
266         return 0;
267 }
268
269 static uint64_t estimate_repack_memory(struct packed_git *pack)
270 {
271         unsigned long nr_objects = approximate_object_count();
272         size_t os_cache, heap;
273
274         if (!pack || !nr_objects)
275                 return 0;
276
277         /*
278          * First we have to scan through at least one pack.
279          * Assume enough room in OS file cache to keep the entire pack
280          * or we may accidentally evict data of other processes from
281          * the cache.
282          */
283         os_cache = pack->pack_size + pack->index_size;
284         /* then pack-objects needs lots more for book keeping */
285         heap = sizeof(struct object_entry) * nr_objects;
286         /*
287          * internal rev-list --all --objects takes up some memory too,
288          * let's say half of it is for blobs
289          */
290         heap += sizeof(struct blob) * nr_objects / 2;
291         /*
292          * and the other half is for trees (commits and tags are
293          * usually insignificant)
294          */
295         heap += sizeof(struct tree) * nr_objects / 2;
296         /* and then obj_hash[], underestimated in fact */
297         heap += sizeof(struct object *) * nr_objects;
298         /* revindex is used also */
299         heap += sizeof(struct revindex_entry) * nr_objects;
300         /*
301          * read_sha1_file() (either at delta calculation phase, or
302          * writing phase) also fills up the delta base cache
303          */
304         heap += delta_base_cache_limit;
305         /* and of course pack-objects has its own delta cache */
306         heap += max_delta_cache_size;
307
308         return os_cache + heap;
309 }
310
311 static int keep_one_pack(struct string_list_item *item, void *data)
312 {
313         argv_array_pushf(&repack, "--keep-pack=%s", basename(item->string));
314         return 0;
315 }
316
317 static void add_repack_all_option(struct string_list *keep_pack)
318 {
319         if (prune_expire && !strcmp(prune_expire, "now"))
320                 argv_array_push(&repack, "-a");
321         else {
322                 argv_array_push(&repack, "-A");
323                 if (prune_expire)
324                         argv_array_pushf(&repack, "--unpack-unreachable=%s", prune_expire);
325         }
326
327         if (keep_pack)
328                 for_each_string_list(keep_pack, keep_one_pack, NULL);
329 }
330
331 static void add_repack_incremental_option(void)
332 {
333         argv_array_push(&repack, "--no-write-bitmap-index");
334 }
335
336 static int need_to_gc(void)
337 {
338         /*
339          * Setting gc.auto to 0 or negative can disable the
340          * automatic gc.
341          */
342         if (gc_auto_threshold <= 0)
343                 return 0;
344
345         /*
346          * If there are too many loose objects, but not too many
347          * packs, we run "repack -d -l".  If there are too many packs,
348          * we run "repack -A -d -l".  Otherwise we tell the caller
349          * there is no need.
350          */
351         if (too_many_packs()) {
352                 struct string_list keep_pack = STRING_LIST_INIT_NODUP;
353
354                 if (big_pack_threshold) {
355                         find_base_packs(&keep_pack, big_pack_threshold);
356                         if (keep_pack.nr >= gc_auto_pack_limit) {
357                                 big_pack_threshold = 0;
358                                 string_list_clear(&keep_pack, 0);
359                                 find_base_packs(&keep_pack, 0);
360                         }
361                 } else {
362                         struct packed_git *p = find_base_packs(&keep_pack, 0);
363                         uint64_t mem_have, mem_want;
364
365                         mem_have = total_ram();
366                         mem_want = estimate_repack_memory(p);
367
368                         /*
369                          * Only allow 1/2 of memory for pack-objects, leave
370                          * the rest for the OS and other processes in the
371                          * system.
372                          */
373                         if (!mem_have || mem_want < mem_have / 2)
374                                 string_list_clear(&keep_pack, 0);
375                 }
376
377                 add_repack_all_option(&keep_pack);
378                 string_list_clear(&keep_pack, 0);
379         } else if (too_many_loose_objects())
380                 add_repack_incremental_option();
381         else
382                 return 0;
383
384         if (run_hook_le(NULL, "pre-auto-gc", NULL))
385                 return 0;
386         return 1;
387 }
388
389 /* return NULL on success, else hostname running the gc */
390 static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
391 {
392         struct lock_file lock = LOCK_INIT;
393         char my_host[HOST_NAME_MAX + 1];
394         struct strbuf sb = STRBUF_INIT;
395         struct stat st;
396         uintmax_t pid;
397         FILE *fp;
398         int fd;
399         char *pidfile_path;
400
401         if (is_tempfile_active(pidfile))
402                 /* already locked */
403                 return NULL;
404
405         if (xgethostname(my_host, sizeof(my_host)))
406                 xsnprintf(my_host, sizeof(my_host), "unknown");
407
408         pidfile_path = git_pathdup("gc.pid");
409         fd = hold_lock_file_for_update(&lock, pidfile_path,
410                                        LOCK_DIE_ON_ERROR);
411         if (!force) {
412                 static char locking_host[HOST_NAME_MAX + 1];
413                 static char *scan_fmt;
414                 int should_exit;
415
416                 if (!scan_fmt)
417                         scan_fmt = xstrfmt("%s %%%ds", "%"SCNuMAX, HOST_NAME_MAX);
418                 fp = fopen(pidfile_path, "r");
419                 memset(locking_host, 0, sizeof(locking_host));
420                 should_exit =
421                         fp != NULL &&
422                         !fstat(fileno(fp), &st) &&
423                         /*
424                          * 12 hour limit is very generous as gc should
425                          * never take that long. On the other hand we
426                          * don't really need a strict limit here,
427                          * running gc --auto one day late is not a big
428                          * problem. --force can be used in manual gc
429                          * after the user verifies that no gc is
430                          * running.
431                          */
432                         time(NULL) - st.st_mtime <= 12 * 3600 &&
433                         fscanf(fp, scan_fmt, &pid, locking_host) == 2 &&
434                         /* be gentle to concurrent "gc" on remote hosts */
435                         (strcmp(locking_host, my_host) || !kill(pid, 0) || errno == EPERM);
436                 if (fp != NULL)
437                         fclose(fp);
438                 if (should_exit) {
439                         if (fd >= 0)
440                                 rollback_lock_file(&lock);
441                         *ret_pid = pid;
442                         free(pidfile_path);
443                         return locking_host;
444                 }
445         }
446
447         strbuf_addf(&sb, "%"PRIuMAX" %s",
448                     (uintmax_t) getpid(), my_host);
449         write_in_full(fd, sb.buf, sb.len);
450         strbuf_release(&sb);
451         commit_lock_file(&lock);
452         pidfile = register_tempfile(pidfile_path);
453         free(pidfile_path);
454         return NULL;
455 }
456
457 /*
458  * Returns 0 if there was no previous error and gc can proceed, 1 if
459  * gc should not proceed due to an error in the last run. Prints a
460  * message and returns -1 if an error occured while reading gc.log
461  */
462 static int report_last_gc_error(void)
463 {
464         struct strbuf sb = STRBUF_INIT;
465         int ret = 0;
466         ssize_t len;
467         struct stat st;
468         char *gc_log_path = git_pathdup("gc.log");
469
470         if (stat(gc_log_path, &st)) {
471                 if (errno == ENOENT)
472                         goto done;
473
474                 ret = error_errno(_("cannot stat '%s'"), gc_log_path);
475                 goto done;
476         }
477
478         if (st.st_mtime < gc_log_expire_time)
479                 goto done;
480
481         len = strbuf_read_file(&sb, gc_log_path, 0);
482         if (len < 0)
483                 ret = error_errno(_("cannot read '%s'"), gc_log_path);
484         else if (len > 0) {
485                 /*
486                  * A previous gc failed.  Report the error, and don't
487                  * bother with an automatic gc run since it is likely
488                  * to fail in the same way.
489                  */
490                 warning(_("The last gc run reported the following. "
491                                "Please correct the root cause\n"
492                                "and remove %s.\n"
493                                "Automatic cleanup will not be performed "
494                                "until the file is removed.\n\n"
495                                "%s"),
496                             gc_log_path, sb.buf);
497                 ret = 1;
498         }
499         strbuf_release(&sb);
500 done:
501         free(gc_log_path);
502         return ret;
503 }
504
505 static void gc_before_repack(void)
506 {
507         /*
508          * We may be called twice, as both the pre- and
509          * post-daemonized phases will call us, but running these
510          * commands more than once is pointless and wasteful.
511          */
512         static int done = 0;
513         if (done++)
514                 return;
515
516         if (pack_refs && run_command_v_opt(pack_refs_cmd.argv, RUN_GIT_CMD))
517                 die(FAILED_RUN, pack_refs_cmd.argv[0]);
518
519         if (prune_reflogs && run_command_v_opt(reflog.argv, RUN_GIT_CMD))
520                 die(FAILED_RUN, reflog.argv[0]);
521 }
522
523 int cmd_gc(int argc, const char **argv, const char *prefix)
524 {
525         int aggressive = 0;
526         int auto_gc = 0;
527         int quiet = 0;
528         int force = 0;
529         const char *name;
530         pid_t pid;
531         int daemonized = 0;
532         int keep_base_pack = -1;
533         timestamp_t dummy;
534
535         struct option builtin_gc_options[] = {
536                 OPT__QUIET(&quiet, N_("suppress progress reporting")),
537                 { OPTION_STRING, 0, "prune", &prune_expire, N_("date"),
538                         N_("prune unreferenced objects"),
539                         PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire },
540                 OPT_BOOL(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")),
541                 OPT_BOOL_F(0, "auto", &auto_gc, N_("enable auto-gc mode"),
542                            PARSE_OPT_NOCOMPLETE),
543                 OPT_BOOL_F(0, "force", &force,
544                            N_("force running gc even if there may be another gc running"),
545                            PARSE_OPT_NOCOMPLETE),
546                 OPT_BOOL(0, "keep-largest-pack", &keep_base_pack,
547                          N_("repack all other packs except the largest pack")),
548                 OPT_END()
549         };
550
551         if (argc == 2 && !strcmp(argv[1], "-h"))
552                 usage_with_options(builtin_gc_usage, builtin_gc_options);
553
554         argv_array_pushl(&pack_refs_cmd, "pack-refs", "--all", "--prune", NULL);
555         argv_array_pushl(&reflog, "reflog", "expire", "--all", NULL);
556         argv_array_pushl(&repack, "repack", "-d", "-l", NULL);
557         argv_array_pushl(&prune, "prune", "--expire", NULL);
558         argv_array_pushl(&prune_worktrees, "worktree", "prune", "--expire", NULL);
559         argv_array_pushl(&rerere, "rerere", "gc", NULL);
560
561         /* default expiry time, overwritten in gc_config */
562         gc_config();
563         if (parse_expiry_date(gc_log_expire, &gc_log_expire_time))
564                 die(_("failed to parse gc.logexpiry value %s"), gc_log_expire);
565
566         if (pack_refs < 0)
567                 pack_refs = !is_bare_repository();
568
569         argc = parse_options(argc, argv, prefix, builtin_gc_options,
570                              builtin_gc_usage, 0);
571         if (argc > 0)
572                 usage_with_options(builtin_gc_usage, builtin_gc_options);
573
574         if (prune_expire && parse_expiry_date(prune_expire, &dummy))
575                 die(_("failed to parse prune expiry value %s"), prune_expire);
576
577         if (aggressive) {
578                 argv_array_push(&repack, "-f");
579                 if (aggressive_depth > 0)
580                         argv_array_pushf(&repack, "--depth=%d", aggressive_depth);
581                 if (aggressive_window > 0)
582                         argv_array_pushf(&repack, "--window=%d", aggressive_window);
583         }
584         if (quiet)
585                 argv_array_push(&repack, "-q");
586
587         if (auto_gc) {
588                 /*
589                  * Auto-gc should be least intrusive as possible.
590                  */
591                 if (!need_to_gc())
592                         return 0;
593                 if (!quiet) {
594                         if (detach_auto)
595                                 fprintf(stderr, _("Auto packing the repository in background for optimum performance.\n"));
596                         else
597                                 fprintf(stderr, _("Auto packing the repository for optimum performance.\n"));
598                         fprintf(stderr, _("See \"git help gc\" for manual housekeeping.\n"));
599                 }
600                 if (detach_auto) {
601                         int ret = report_last_gc_error();
602                         if (ret < 0)
603                                 /* an I/O error occured, already reported */
604                                 exit(128);
605                         if (ret == 1)
606                                 /* Last gc --auto failed. Skip this one. */
607                                 return 0;
608
609                         if (lock_repo_for_gc(force, &pid))
610                                 return 0;
611                         gc_before_repack(); /* dies on failure */
612                         delete_tempfile(&pidfile);
613
614                         /*
615                          * failure to daemonize is ok, we'll continue
616                          * in foreground
617                          */
618                         daemonized = !daemonize();
619                 }
620         } else {
621                 struct string_list keep_pack = STRING_LIST_INIT_NODUP;
622
623                 if (keep_base_pack != -1) {
624                         if (keep_base_pack)
625                                 find_base_packs(&keep_pack, 0);
626                 } else if (big_pack_threshold) {
627                         find_base_packs(&keep_pack, big_pack_threshold);
628                 }
629
630                 add_repack_all_option(&keep_pack);
631                 string_list_clear(&keep_pack, 0);
632         }
633
634         name = lock_repo_for_gc(force, &pid);
635         if (name) {
636                 if (auto_gc)
637                         return 0; /* be quiet on --auto */
638                 die(_("gc is already running on machine '%s' pid %"PRIuMAX" (use --force if not)"),
639                     name, (uintmax_t)pid);
640         }
641
642         if (daemonized) {
643                 hold_lock_file_for_update(&log_lock,
644                                           git_path("gc.log"),
645                                           LOCK_DIE_ON_ERROR);
646                 dup2(get_lock_file_fd(&log_lock), 2);
647                 sigchain_push_common(process_log_file_on_signal);
648                 atexit(process_log_file_at_exit);
649         }
650
651         gc_before_repack();
652
653         if (!repository_format_precious_objects) {
654                 close_object_store(the_repository->objects);
655                 if (run_command_v_opt(repack.argv, RUN_GIT_CMD))
656                         die(FAILED_RUN, repack.argv[0]);
657
658                 if (prune_expire) {
659                         argv_array_push(&prune, prune_expire);
660                         if (quiet)
661                                 argv_array_push(&prune, "--no-progress");
662                         if (repository_format_partial_clone)
663                                 argv_array_push(&prune,
664                                                 "--exclude-promisor-objects");
665                         if (run_command_v_opt(prune.argv, RUN_GIT_CMD))
666                                 die(FAILED_RUN, prune.argv[0]);
667                 }
668         }
669
670         if (prune_worktrees_expire) {
671                 argv_array_push(&prune_worktrees, prune_worktrees_expire);
672                 if (run_command_v_opt(prune_worktrees.argv, RUN_GIT_CMD))
673                         die(FAILED_RUN, prune_worktrees.argv[0]);
674         }
675
676         if (run_command_v_opt(rerere.argv, RUN_GIT_CMD))
677                 die(FAILED_RUN, rerere.argv[0]);
678
679         report_garbage = report_pack_garbage;
680         reprepare_packed_git(the_repository);
681         if (pack_garbage.nr > 0) {
682                 close_object_store(the_repository->objects);
683                 clean_pack_garbage();
684         }
685
686         prepare_repo_settings(the_repository);
687         if (the_repository->settings.gc_write_commit_graph == 1)
688                 write_commit_graph_reachable(get_object_directory(),
689                                              !quiet && !daemonized ? COMMIT_GRAPH_WRITE_PROGRESS : 0,
690                                              NULL);
691
692         if (auto_gc && too_many_loose_objects())
693                 warning(_("There are too many unreachable loose objects; "
694                         "run 'git prune' to remove them."));
695
696         if (!daemonized)
697                 unlink(git_path("gc.log"));
698
699         return 0;
700 }