aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/depdb.hxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2/depdb.hxx')
-rw-r--r--libbuild2/depdb.hxx77
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);