@@ -56,7 +56,8 @@ static int my_validate_index(const struct cache_time *mtime_reported)
5656 mtime_observed_on_disk .nsec = ST_MTIME_NSEC (st );
5757 if ((mtime_observed_on_disk .sec != mtime_reported -> sec ) ||
5858 (mtime_observed_on_disk .nsec != mtime_reported -> nsec )) {
59- trace_printf_key (& trace_deserialize , "index mtime changed [des %d.%d][obs %d.%d]" ,
59+ trace_printf_key (& trace_deserialize ,
60+ "index mtime changed [des %d %d][obs %d %d]" ,
6061 mtime_reported -> sec , mtime_reported -> nsec ,
6162 mtime_observed_on_disk .sec , mtime_observed_on_disk .nsec );
6263 return DESERIALIZE_ERR ;
@@ -545,6 +546,8 @@ static inline int my_strcmp_null(const char *a, const char *b)
545546
546547static int wt_deserialize_fd (const struct wt_status * cmd_s , struct wt_status * des_s , int fd )
547548{
549+ memset (des_s , 0 , sizeof (* des_s ));
550+
548551 /*
549552 * Check the path spec on the current command
550553 */
@@ -668,33 +671,127 @@ static int wt_deserialize_fd(const struct wt_status *cmd_s, struct wt_status *de
668671 return DESERIALIZE_OK ;
669672}
670673
674+ static struct cache_time deserialize_prev_mtime = { 0 , 0 };
675+
676+ static int try_deserialize_read_from_file_1 (const struct wt_status * cmd_s ,
677+ const char * path ,
678+ struct wt_status * des_s )
679+ {
680+ struct stat st ;
681+ int result ;
682+ int fd ;
683+
684+ /*
685+ * If we are spinning waiting for the status cache to become
686+ * valid, skip re-reading it if the mtime has not changed
687+ * since the last time we read it.
688+ */
689+ if (lstat (path , & st )) {
690+ trace_printf_key (& trace_deserialize ,
691+ "could not lstat '%s'" , path );
692+ return DESERIALIZE_ERR ;
693+ }
694+ if (st .st_mtime == deserialize_prev_mtime .sec &&
695+ ST_MTIME_NSEC (st ) == deserialize_prev_mtime .nsec ) {
696+ trace_printf_key (& trace_deserialize ,
697+ "mtime has not changed '%s'" , path );
698+ return DESERIALIZE_ERR ;
699+ }
700+
701+ fd = xopen (path , O_RDONLY );
702+ if (fd == -1 ) {
703+ trace_printf_key (& trace_deserialize ,
704+ "could not read '%s'" , path );
705+ return DESERIALIZE_ERR ;
706+ }
707+
708+ deserialize_prev_mtime .sec = st .st_mtime ;
709+ deserialize_prev_mtime .nsec = ST_MTIME_NSEC (st );
710+
711+ trace_printf_key (& trace_deserialize ,
712+ "reading serialization file (%d %d) '%s'" ,
713+ deserialize_prev_mtime .sec ,
714+ deserialize_prev_mtime .nsec ,
715+ path );
716+
717+ result = wt_deserialize_fd (cmd_s , des_s , fd );
718+ close (fd );
719+
720+ return result ;
721+ }
722+
723+ static int try_deserialize_read_from_file (const struct wt_status * cmd_s ,
724+ const char * path ,
725+ enum wt_status_deserialize_wait dw ,
726+ struct wt_status * des_s )
727+ {
728+ int k , limit ;
729+ int result = DESERIALIZE_ERR ;
730+
731+ /*
732+ * For "fail" or "no", try exactly once to read the status cache.
733+ * Return an error if the file is stale.
734+ */
735+ if (dw == DESERIALIZE_WAIT__FAIL || dw == DESERIALIZE_WAIT__NO )
736+ return try_deserialize_read_from_file_1 (cmd_s , path , des_s );
737+
738+ /*
739+ * Wait for the status cache file to refresh. Wait duration can
740+ * be in tenths of a second or unlimited. Poll every 100ms.
741+ */
742+ if (dw == DESERIALIZE_WAIT__BLOCK ) {
743+ /*
744+ * Convert "unlimited" to 1 day.
745+ */
746+ limit = 10 * 60 * 60 * 24 ;
747+ } else {
748+ /* spin for dw tenths of a second */
749+ limit = dw ;
750+ }
751+ for (k = 0 ; k < limit ; k ++ ) {
752+ result = try_deserialize_read_from_file_1 (
753+ cmd_s , path , des_s );
754+
755+ if (result == DESERIALIZE_OK )
756+ break ;
757+
758+ sleep_millisec (100 );
759+ }
760+
761+ trace_printf_key (& trace_deserialize ,
762+ "wait polled=%d result=%d '%s'" ,
763+ k , result , path );
764+ return result ;
765+ }
766+
671767/*
672- * Read raw serialized status data from the given file
768+ * Read raw serialized status data from the given file (or STDIN).
673769 *
674770 * Verify that the args specified in the current command
675771 * are compatible with the deserialized data (such as "-uno").
676772 *
677773 * Copy display-related fields from the current command
678774 * into the deserialized data (so that the user can request
679775 * long or short as they please).
776+ *
777+ * Print status report using cached data.
680778 */
681779int wt_status_deserialize (const struct wt_status * cmd_s ,
682- const char * path )
780+ const char * path ,
781+ enum wt_status_deserialize_wait dw )
683782{
684783 struct wt_status des_s ;
685784 int result ;
686785
687786 if (path && * path && strcmp (path , "0" )) {
688- int fd = xopen (path , O_RDONLY );
689- if (fd == -1 ) {
690- trace_printf_key (& trace_deserialize , "could not read '%s'" , path );
691- return DESERIALIZE_ERR ;
692- }
693- trace_printf_key (& trace_deserialize , "reading serialization file '%s'" , path );
694- result = wt_deserialize_fd (cmd_s , & des_s , fd );
695- close (fd );
787+ result = try_deserialize_read_from_file (cmd_s , path , dw , & des_s );
696788 } else {
697789 trace_printf_key (& trace_deserialize , "reading stdin" );
790+
791+ /*
792+ * Read status cache data from stdin. Ignore the deserialize-wait
793+ * term, since we cannot read stdin multiple times.
794+ */
698795 result = wt_deserialize_fd (cmd_s , & des_s , 0 );
699796 }
700797
0 commit comments