@@ -167,11 +167,69 @@ static int need_to_gc(void)
167
167
return 1 ;
168
168
}
169
169
170
+ /* return NULL on success, else hostname running the gc */
171
+ static const char * lock_repo_for_gc (int force , pid_t * ret_pid )
172
+ {
173
+ static struct lock_file lock ;
174
+ static char locking_host [128 ];
175
+ char my_host [128 ];
176
+ struct strbuf sb = STRBUF_INIT ;
177
+ struct stat st ;
178
+ uintmax_t pid ;
179
+ FILE * fp ;
180
+ int fd , should_exit ;
181
+
182
+ if (gethostname (my_host , sizeof (my_host )))
183
+ strcpy (my_host , "unknown" );
184
+
185
+ fd = hold_lock_file_for_update (& lock , git_path ("gc.pid" ),
186
+ LOCK_DIE_ON_ERROR );
187
+ if (!force ) {
188
+ fp = fopen (git_path ("gc.pid" ), "r" );
189
+ memset (locking_host , 0 , sizeof (locking_host ));
190
+ should_exit =
191
+ fp != NULL &&
192
+ !fstat (fileno (fp ), & st ) &&
193
+ /*
194
+ * 12 hour limit is very generous as gc should
195
+ * never take that long. On the other hand we
196
+ * don't really need a strict limit here,
197
+ * running gc --auto one day late is not a big
198
+ * problem. --force can be used in manual gc
199
+ * after the user verifies that no gc is
200
+ * running.
201
+ */
202
+ time (NULL ) - st .st_mtime <= 12 * 3600 &&
203
+ fscanf (fp , "%" PRIuMAX " %127c" , & pid , locking_host ) == 2 &&
204
+ /* be gentle to concurrent "gc" on remote hosts */
205
+ (strcmp (locking_host , my_host ) || !kill (pid , 0 ));
206
+ if (fp != NULL )
207
+ fclose (fp );
208
+ if (should_exit ) {
209
+ if (fd >= 0 )
210
+ rollback_lock_file (& lock );
211
+ * ret_pid = pid ;
212
+ return locking_host ;
213
+ }
214
+ }
215
+
216
+ strbuf_addf (& sb , "%" PRIuMAX " %s" ,
217
+ (uintmax_t ) getpid (), my_host );
218
+ write_in_full (fd , sb .buf , sb .len );
219
+ strbuf_release (& sb );
220
+ commit_lock_file (& lock );
221
+
222
+ return NULL ;
223
+ }
224
+
170
225
int cmd_gc (int argc , const char * * argv , const char * prefix )
171
226
{
172
227
int aggressive = 0 ;
173
228
int auto_gc = 0 ;
174
229
int quiet = 0 ;
230
+ int force = 0 ;
231
+ const char * name ;
232
+ pid_t pid ;
175
233
176
234
struct option builtin_gc_options [] = {
177
235
OPT__QUIET (& quiet , N_ ("suppress progress reporting" )),
@@ -180,6 +238,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
180
238
PARSE_OPT_OPTARG , NULL , (intptr_t )prune_expire },
181
239
OPT_BOOLEAN (0 , "aggressive" , & aggressive , N_ ("be more thorough (increased runtime)" )),
182
240
OPT_BOOLEAN (0 , "auto" , & auto_gc , N_ ("enable auto-gc mode" )),
241
+ OPT_BOOL (0 , "force" , & force , N_ ("force running gc even if there may be another gc running" )),
183
242
OPT_END ()
184
243
};
185
244
@@ -225,6 +284,14 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
225
284
} else
226
285
add_repack_all_option ();
227
286
287
+ name = lock_repo_for_gc (force , & pid );
288
+ if (name ) {
289
+ if (auto_gc )
290
+ return 0 ; /* be quiet on --auto */
291
+ die (_ ("gc is already running on machine '%s' pid %" PRIuMAX " (use --force if not)" ),
292
+ name , (uintmax_t )pid );
293
+ }
294
+
228
295
if (pack_refs && run_command_v_opt (pack_refs_cmd .argv , RUN_GIT_CMD ))
229
296
return error (FAILED_RUN , pack_refs_cmd .argv [0 ]);
230
297
0 commit comments