@@ -62,7 +62,8 @@ static int my_validate_index(const char *path, const struct cache_time *mtime_re
6262 mtime_observed_on_disk .nsec = ST_MTIME_NSEC (st );
6363 if ((mtime_observed_on_disk .sec != mtime_reported -> sec ) ||
6464 (mtime_observed_on_disk .nsec != mtime_reported -> nsec )) {
65- trace_printf_key (& trace_deserialize , "index mtime changed [des %d.%d][obs %d.%d]" ,
65+ trace_printf_key (& trace_deserialize ,
66+ "index mtime changed [des %d %d][obs %d %d]" ,
6667 mtime_reported -> sec , mtime_reported -> nsec ,
6768 mtime_observed_on_disk .sec , mtime_observed_on_disk .nsec );
6869 return DESERIALIZE_ERR ;
@@ -552,6 +553,8 @@ static inline int my_strcmp_null(const char *a, const char *b)
552553
553554static int wt_deserialize_fd (const struct wt_status * cmd_s , struct wt_status * des_s , int fd )
554555{
556+ memset (des_s , 0 , sizeof (* des_s ));
557+
555558 /*
556559 * Check the path spec on the current command
557560 */
@@ -681,34 +684,128 @@ static int wt_deserialize_fd(const struct wt_status *cmd_s, struct wt_status *de
681684 return DESERIALIZE_OK ;
682685}
683686
687+ static struct cache_time deserialize_prev_mtime = { 0 , 0 };
688+
689+ static int try_deserialize_read_from_file_1 (const struct wt_status * cmd_s ,
690+ const char * path ,
691+ struct wt_status * des_s )
692+ {
693+ struct stat st ;
694+ int result ;
695+ int fd ;
696+
697+ /*
698+ * If we are spinning waiting for the status cache to become
699+ * valid, skip re-reading it if the mtime has not changed
700+ * since the last time we read it.
701+ */
702+ if (lstat (path , & st )) {
703+ trace_printf_key (& trace_deserialize ,
704+ "could not lstat '%s'" , path );
705+ return DESERIALIZE_ERR ;
706+ }
707+ if ((uint32_t )st .st_mtime == deserialize_prev_mtime .sec &&
708+ ST_MTIME_NSEC (st ) == deserialize_prev_mtime .nsec ) {
709+ trace_printf_key (& trace_deserialize ,
710+ "mtime has not changed '%s'" , path );
711+ return DESERIALIZE_ERR ;
712+ }
713+
714+ fd = xopen (path , O_RDONLY );
715+ if (fd == -1 ) {
716+ trace_printf_key (& trace_deserialize ,
717+ "could not read '%s'" , path );
718+ return DESERIALIZE_ERR ;
719+ }
720+
721+ deserialize_prev_mtime .sec = st .st_mtime ;
722+ deserialize_prev_mtime .nsec = ST_MTIME_NSEC (st );
723+
724+ trace_printf_key (& trace_deserialize ,
725+ "reading serialization file (%d %d) '%s'" ,
726+ deserialize_prev_mtime .sec ,
727+ deserialize_prev_mtime .nsec ,
728+ path );
729+
730+ result = wt_deserialize_fd (cmd_s , des_s , fd );
731+ close (fd );
732+
733+ return result ;
734+ }
735+
736+ static int try_deserialize_read_from_file (const struct wt_status * cmd_s ,
737+ const char * path ,
738+ enum wt_status_deserialize_wait dw ,
739+ struct wt_status * des_s )
740+ {
741+ int k , limit ;
742+ int result = DESERIALIZE_ERR ;
743+
744+ /*
745+ * For "fail" or "no", try exactly once to read the status cache.
746+ * Return an error if the file is stale.
747+ */
748+ if (dw == DESERIALIZE_WAIT__FAIL || dw == DESERIALIZE_WAIT__NO )
749+ return try_deserialize_read_from_file_1 (cmd_s , path , des_s );
750+
751+ /*
752+ * Wait for the status cache file to refresh. Wait duration can
753+ * be in tenths of a second or unlimited. Poll every 100ms.
754+ */
755+ if (dw == DESERIALIZE_WAIT__BLOCK ) {
756+ /*
757+ * Convert "unlimited" to 1 day.
758+ */
759+ limit = 10 * 60 * 60 * 24 ;
760+ } else {
761+ /* spin for dw tenths of a second */
762+ limit = dw ;
763+ }
764+ for (k = 0 ; k < limit ; k ++ ) {
765+ result = try_deserialize_read_from_file_1 (
766+ cmd_s , path , des_s );
767+
768+ if (result == DESERIALIZE_OK )
769+ break ;
770+
771+ sleep_millisec (100 );
772+ }
773+
774+ trace_printf_key (& trace_deserialize ,
775+ "wait polled=%d result=%d '%s'" ,
776+ k , result , path );
777+ return result ;
778+ }
779+
684780/*
685- * Read raw serialized status data from the given file
781+ * Read raw serialized status data from the given file (or STDIN).
686782 *
687783 * Verify that the args specified in the current command
688784 * are compatible with the deserialized data (such as "-uno").
689785 *
690786 * Copy display-related fields from the current command
691787 * into the deserialized data (so that the user can request
692788 * long or short as they please).
789+ *
790+ * Print status report using cached data.
693791 */
694792int wt_status_deserialize (const struct wt_status * cmd_s ,
695- const char * path )
793+ const char * path ,
794+ enum wt_status_deserialize_wait dw )
696795{
697796 struct wt_status des_s ;
698797 int result ;
699798 struct string_list_item * change ;
700799
701800 if (path && * path && strcmp (path , "0" )) {
702- int fd = xopen (path , O_RDONLY );
703- if (fd == -1 ) {
704- trace_printf_key (& trace_deserialize , "could not read '%s'" , path );
705- return DESERIALIZE_ERR ;
706- }
707- trace_printf_key (& trace_deserialize , "reading serialization file '%s'" , path );
708- result = wt_deserialize_fd (cmd_s , & des_s , fd );
709- close (fd );
801+ result = try_deserialize_read_from_file (cmd_s , path , dw , & des_s );
710802 } else {
711803 trace_printf_key (& trace_deserialize , "reading stdin" );
804+
805+ /*
806+ * Read status cache data from stdin. Ignore the deserialize-wait
807+ * term, since we cannot read stdin multiple times.
808+ */
712809 result = wt_deserialize_fd (cmd_s , & des_s , 0 );
713810 }
714811
0 commit comments