diff options
Diffstat (limited to 'libbuild2/depdb.hxx')
-rw-r--r-- | libbuild2/depdb.hxx | 77 |
1 files changed, 63 insertions, 14 deletions
diff --git a/libbuild2/depdb.hxx b/libbuild2/depdb.hxx index abc2565..5855c3f 100644 --- a/libbuild2/depdb.hxx +++ b/libbuild2/depdb.hxx @@ -62,20 +62,23 @@ namespace build2 // struct LIBBUILD2_SYMEXPORT depdb_base { - explicit - depdb_base (const path&, timestamp); + // Implementation details. + // + enum class state {read, read_eof, write}; + depdb_base (const path&, bool ro, state, optional<uint64_t> pos = nullopt); ~depdb_base (); - enum class state {read, read_eof, write} state_; + state state_; + bool ro_; union { - ifdstream is_; // read, read_eof + ifdstream is_; // read, read_eof, (ro && write) ofdstream os_; // write }; - butl::fdbuf* buf_; // Current buffer (for tellg()/tellp()). + butl::fdstreambuf* buf_; // Current buffer (for tellg()). }; class LIBBUILD2_SYMEXPORT depdb: private depdb_base @@ -90,31 +93,77 @@ namespace build2 // close() even if otherwise no modifications are necessary (i.e., the // database is in the read mode and is at eof). // - path_type path; - timestamp mtime; - bool touch; + // If touch is present then update the database modification time in + // close() even if otherwise no modifications are necessary (i.e., the + // database is in the read mode and is at eof). Specifically, if touch is + // timestamp_unknown, then set mtime to the current (filesystem) time. + // Otherwise, set it to the specified time (which should be sourced from + // the filesystem, see touch_file() for details). + // + path_type path; + timestamp mtime; + optional<timestamp> touch; // Open the database for reading. Note that if the file does not exist, // has wrong format version, or is corrupt, then the database will be // immediately switched to writing. // + // If read_only is true, then don't actually make any modifications to the + // database file. In other words, the database is still nominally switched + // to writing but without any filesystem changes. Note that calling any + // write-only functions (write(), touch, etc) on such a database is + // illegal. + // // The failure commonly happens when the user tries to stash the target in // a non-existent subdirectory but forgets to add the corresponding fsdir{} // prerequisite. That's why the issued diagnostics may provide the // corresponding hint. // explicit - depdb (path_type); + depdb (path_type, bool read_only = false); + + struct reopen_state + { + path_type path; + uint64_t pos; + timestamp mtime; + }; + + // Reopen the database for writing. The reopen state must have been + // obtained by calling close_to_reopen() below. Besides opening the file + // and adjusting its write position, this constructor also sets touch to + // the timestamp returned by close_to_reopen() to help maintain the + // "database mtime is before target mtime" invariant. + // + // This functionality is primarily useful to handle dynamic dependency + // information that is produced as a byproduct of compilation. In this + // case the "static" part of the database is written in match and the + // "dynamic" part -- in execute. + // + explicit + depdb (reopen_state); // Close the database. If this function is not called, then the database // may be left in the old/currupt state. Note that in the read mode this // function will "chop off" lines that haven't been read. // // Make sure to also call check_mtime() after updating the target to - // perform the target/database modification times sanity checks. + // perform the target/database modification times sanity checks. Pass + // false to close() to avoid unnecessary work if using the static version + // of check_mtime() (or not using it at all for some reason). // void - close (); + close (bool mtime_check = true); + + // Temporarily close the database to be reopened for writing later. + // Besides the file path and write position also return the database file + // modification time after closing. + // + // Note that after this call the resulting database file is valid and if + // it's not reopened later, the result is equivalent to calling close(). + // + reopen_state + close_to_reopen (); // Flush any unwritten data to disk. This is primarily useful when reusing // a (partially written) database as an input to external programs (e.g., @@ -128,7 +177,7 @@ namespace build2 // Note that it would also be good to compare the target timestamp against // the newest prerequisite. However, obtaining this information would cost // extra (see execute_prerequisites()). So maybe later, if we get a case - // where this is a problem (in a sense, the database is a buffer between + // where this is a problem (in a sense, the database is a barrier between // prerequisites and the target). // void @@ -149,7 +198,7 @@ namespace build2 // the next line in the database (which you are free to move from). If you // then call write(), this line will be overwritten. // - // If the result is NULL, then it means no next line is unavailable. This + // If the result is NULL, then it means no next line is available. This // can be due to several reasons: // // - eof reached (you can detect this by calling more() before read()) @@ -262,7 +311,7 @@ namespace build2 depdb& operator= (const depdb&) = delete; private: - depdb (path_type&&, timestamp); + depdb (path_type&&, bool, timestamp); void change (bool truncate = true); |