@@ -61,7 +61,8 @@ static int my_validate_index(const struct cache_time *mtime_reported)
6161 mtime_observed_on_disk .nsec = ST_MTIME_NSEC (st );
6262 if ((mtime_observed_on_disk .sec != mtime_reported -> sec ) ||
6363 (mtime_observed_on_disk .nsec != mtime_reported -> nsec )) {
64- trace_printf_key (& trace_deserialize , "index mtime changed [des %d.%d][obs %d.%d]" ,
64+ trace_printf_key (& trace_deserialize ,
65+ "index mtime changed [des %d %d][obs %d %d]" ,
6566 mtime_reported -> sec , mtime_reported -> nsec ,
6667 mtime_observed_on_disk .sec , mtime_observed_on_disk .nsec );
6768 return DESERIALIZE_ERR ;
@@ -553,6 +554,8 @@ static inline int my_strcmp_null(const char *a, const char *b)
553554
554555static int wt_deserialize_fd (const struct wt_status * cmd_s , struct wt_status * des_s , int fd )
555556{
557+ memset (des_s , 0 , sizeof (* des_s ));
558+
556559 /*
557560 * Check the path spec on the current command
558561 */
@@ -676,33 +679,127 @@ static int wt_deserialize_fd(const struct wt_status *cmd_s, struct wt_status *de
676679 return DESERIALIZE_OK ;
677680}
678681
682+ static struct cache_time deserialize_prev_mtime = { 0 , 0 };
683+
684+ static int try_deserialize_read_from_file_1 (const struct wt_status * cmd_s ,
685+ const char * path ,
686+ struct wt_status * des_s )
687+ {
688+ struct stat st ;
689+ int result ;
690+ int fd ;
691+
692+ /*
693+ * If we are spinning waiting for the status cache to become
694+ * valid, skip re-reading it if the mtime has not changed
695+ * since the last time we read it.
696+ */
697+ if (lstat (path , & st )) {
698+ trace_printf_key (& trace_deserialize ,
699+ "could not lstat '%s'" , path );
700+ return DESERIALIZE_ERR ;
701+ }
702+ if (st .st_mtime == deserialize_prev_mtime .sec &&
703+ ST_MTIME_NSEC (st ) == deserialize_prev_mtime .nsec ) {
704+ trace_printf_key (& trace_deserialize ,
705+ "mtime has not changed '%s'" , path );
706+ return DESERIALIZE_ERR ;
707+ }
708+
709+ fd = xopen (path , O_RDONLY );
710+ if (fd == -1 ) {
711+ trace_printf_key (& trace_deserialize ,
712+ "could not read '%s'" , path );
713+ return DESERIALIZE_ERR ;
714+ }
715+
716+ deserialize_prev_mtime .sec = st .st_mtime ;
717+ deserialize_prev_mtime .nsec = ST_MTIME_NSEC (st );
718+
719+ trace_printf_key (& trace_deserialize ,
720+ "reading serialization file (%d %d) '%s'" ,
721+ deserialize_prev_mtime .sec ,
722+ deserialize_prev_mtime .nsec ,
723+ path );
724+
725+ result = wt_deserialize_fd (cmd_s , des_s , fd );
726+ close (fd );
727+
728+ return result ;
729+ }
730+
731+ static int try_deserialize_read_from_file (const struct wt_status * cmd_s ,
732+ const char * path ,
733+ enum wt_status_deserialize_wait dw ,
734+ struct wt_status * des_s )
735+ {
736+ int k , limit ;
737+ int result = DESERIALIZE_ERR ;
738+
739+ /*
740+ * For "fail" or "no", try exactly once to read the status cache.
741+ * Return an error if the file is stale.
742+ */
743+ if (dw == DESERIALIZE_WAIT__FAIL || dw == DESERIALIZE_WAIT__NO )
744+ return try_deserialize_read_from_file_1 (cmd_s , path , des_s );
745+
746+ /*
747+ * Wait for the status cache file to refresh. Wait duration can
748+ * be in tenths of a second or unlimited. Poll every 100ms.
749+ */
750+ if (dw == DESERIALIZE_WAIT__BLOCK ) {
751+ /*
752+ * Convert "unlimited" to 1 day.
753+ */
754+ limit = 10 * 60 * 60 * 24 ;
755+ } else {
756+ /* spin for dw tenths of a second */
757+ limit = dw ;
758+ }
759+ for (k = 0 ; k < limit ; k ++ ) {
760+ result = try_deserialize_read_from_file_1 (
761+ cmd_s , path , des_s );
762+
763+ if (result == DESERIALIZE_OK )
764+ break ;
765+
766+ sleep_millisec (100 );
767+ }
768+
769+ trace_printf_key (& trace_deserialize ,
770+ "wait polled=%d result=%d '%s'" ,
771+ k , result , path );
772+ return result ;
773+ }
774+
679775/*
680- * Read raw serialized status data from the given file
776+ * Read raw serialized status data from the given file (or STDIN).
681777 *
682778 * Verify that the args specified in the current command
683779 * are compatible with the deserialized data (such as "-uno").
684780 *
685781 * Copy display-related fields from the current command
686782 * into the deserialized data (so that the user can request
687783 * long or short as they please).
784+ *
785+ * Print status report using cached data.
688786 */
689787int wt_status_deserialize (const struct wt_status * cmd_s ,
690- const char * path )
788+ const char * path ,
789+ enum wt_status_deserialize_wait dw )
691790{
692791 struct wt_status des_s ;
693792 int result ;
694793
695794 if (path && * path && strcmp (path , "0" )) {
696- int fd = xopen (path , O_RDONLY );
697- if (fd == -1 ) {
698- trace_printf_key (& trace_deserialize , "could not read '%s'" , path );
699- return DESERIALIZE_ERR ;
700- }
701- trace_printf_key (& trace_deserialize , "reading serialization file '%s'" , path );
702- result = wt_deserialize_fd (cmd_s , & des_s , fd );
703- close (fd );
795+ result = try_deserialize_read_from_file (cmd_s , path , dw , & des_s );
704796 } else {
705797 trace_printf_key (& trace_deserialize , "reading stdin" );
798+
799+ /*
800+ * Read status cache data from stdin. Ignore the deserialize-wait
801+ * term, since we cannot read stdin multiple times.
802+ */
706803 result = wt_deserialize_fd (cmd_s , & des_s , 0 );
707804 }
708805
0 commit comments