Store timespec for buffer fs timestamps, not just time_t

time_t has a resolution of one second, which cause troubles when
a file changes multiple time during that same second.
This commit is contained in:
Maxime Coste 2015-09-27 11:55:34 +01:00
parent 122a799ecb
commit e2720f1fbe
7 changed files with 33 additions and 23 deletions

View File

@ -18,7 +18,7 @@ namespace Kakoune
{
Buffer::Buffer(String name, Flags flags, BufferLines lines,
time_t fs_timestamp)
timespec fs_timestamp)
: Scope(GlobalScope::instance()),
m_name((flags & Flags::File) ? real_path(parse_filename(name)) : std::move(name)),
m_display_name((flags & Flags::File) ? compact_path(m_name) : m_name),
@ -160,7 +160,7 @@ struct Buffer::Modification
}
};
void Buffer::reload(BufferLines lines, time_t fs_timestamp)
void Buffer::reload(BufferLines lines, timespec fs_timestamp)
{
if (lines.empty())
lines.emplace_back(StringData::create("\n"));
@ -531,13 +531,13 @@ ByteCoord Buffer::char_prev(ByteCoord coord) const
return coord;
}
time_t Buffer::fs_timestamp() const
timespec Buffer::fs_timestamp() const
{
kak_assert(m_flags & Flags::File);
return m_fs_timestamp;
}
void Buffer::set_fs_timestamp(time_t ts)
void Buffer::set_fs_timestamp(timespec ts)
{
kak_assert(m_flags & Flags::File);
m_fs_timestamp = ts;

View File

@ -14,7 +14,7 @@ namespace Kakoune
class Buffer;
constexpr time_t InvalidTime = 0;
constexpr timespec InvalidTime = { -1, -1 };
// A BufferIterator permits to iterate over the characters of a buffer
class BufferIterator
@ -79,7 +79,7 @@ public:
};
Buffer(String name, Flags flags, BufferLines lines = {},
time_t fs_timestamp = InvalidTime);
timespec fs_timestamp = InvalidTime);
Buffer(const Buffer&) = delete;
Buffer& operator= (const Buffer&) = delete;
~Buffer();
@ -93,8 +93,8 @@ public:
BufferIterator erase(BufferIterator begin, BufferIterator end);
size_t timestamp() const;
time_t fs_timestamp() const;
void set_fs_timestamp(time_t ts);
timespec fs_timestamp() const;
void set_fs_timestamp(timespec ts);
void commit_undo_group();
bool undo();
@ -152,7 +152,7 @@ public:
void run_hook_in_own_context(StringView hook_name, StringView param);
void reload(BufferLines lines, time_t fs_timestamp = InvalidTime);
void reload(BufferLines lines, timespec fs_timestamp = InvalidTime);
void check_invariant() const;
@ -213,7 +213,7 @@ private:
Vector<Change, MemoryDomain::BufferMeta> m_changes;
time_t m_fs_timestamp;
timespec m_fs_timestamp;
// Values are just data holding by the buffer, they are not part of its
// observable state

View File

@ -47,7 +47,7 @@ ByteCount get_byte_to_column(const Buffer& buffer, CharCount tabstop, CharCoord
}
Buffer* create_buffer_from_data(StringView data, StringView name,
Buffer::Flags flags, time_t fs_timestamp)
Buffer::Flags flags, timespec fs_timestamp)
{
bool bom = false, crlf = false;
@ -98,7 +98,7 @@ Buffer* create_fifo_buffer(String name, int fd, bool scroll)
if (buffer)
{
buffer->flags() |= Buffer::Flags::NoUndo;
buffer->reload({"\n"_ss}, 0);
buffer->reload({"\n"_ss}, InvalidTime);
}
else
buffer = new Buffer(std::move(name), Buffer::Flags::Fifo | Buffer::Flags::NoUndo);

View File

@ -34,7 +34,7 @@ Buffer* create_fifo_buffer(String name, int fd, bool scroll = false);
Buffer* create_buffer_from_data(StringView data, StringView name,
Buffer::Flags flags,
time_t fs_timestamp = InvalidTime);
timespec fs_timestamp = InvalidTime);
void write_to_debug_buffer(StringView str);

View File

@ -246,7 +246,7 @@ void Client::check_if_buffer_needs_reloading()
return;
const String& filename = buffer.name();
time_t ts = get_fs_timestamp(filename);
timespec ts = get_fs_timestamp(filename);
if (ts == InvalidTime or ts == buffer.fs_timestamp())
return;
if (reload == Ask)

View File

@ -180,13 +180,13 @@ Buffer* create_buffer_from_file(StringView filename)
throw file_access_error(real_filename, "is a directory");
if (S_ISFIFO(st.st_mode)) // Do not try to read fifos, use them as write only
return create_buffer_from_data({}, real_filename,
Buffer::Flags::File, st.st_mtime);
Buffer::Flags::File, st.st_mtim);
const char* data = (const char*)mmap(nullptr, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
auto unmap = on_scope_end([&]{ munmap((void*)data, st.st_size); });
return create_buffer_from_data({data, data + st.st_size}, real_filename,
Buffer::Flags::File, st.st_mtime);
Buffer::Flags::File, st.st_mtim);
}
static void write(int fd, StringView data)
@ -423,11 +423,11 @@ Vector<String> complete_command(StringView prefix, ByteCount cursor_pos)
return res;
}
typedef decltype(stat::st_mtime) TimeSpec;
typedef decltype(stat::st_mtim) TimeSpec;
struct CommandCache
{
TimeSpec mtime = {};
TimeSpec mtim = {};
Vector<String> commands;
};
static UnorderedMap<String, CommandCache, MemoryDomain::Commands> command_cache;
@ -442,7 +442,7 @@ Vector<String> complete_command(StringView prefix, ByteCount cursor_pos)
continue;
auto& cache = command_cache[dirname];
if (memcmp(&cache.mtime, &st.st_mtime, sizeof(TimeSpec)) != 0)
if (memcmp(&cache.mtim, &st.st_mtim, sizeof(TimeSpec)) != 0)
{
auto filter = [&](const dirent& entry) {
struct stat st;
@ -457,7 +457,7 @@ Vector<String> complete_command(StringView prefix, ByteCount cursor_pos)
};
cache.commands = list_files("", dirname, filter);
memcpy(&cache.mtime, &st.st_mtime, sizeof(TimeSpec));
memcpy(&cache.mtim, &st.st_mtim, sizeof(TimeSpec));
}
for (auto& cmd : cache.commands)
{
@ -471,12 +471,12 @@ Vector<String> complete_command(StringView prefix, ByteCount cursor_pos)
return res;
}
time_t get_fs_timestamp(StringView filename)
timespec get_fs_timestamp(StringView filename)
{
struct stat st;
if (stat(filename.zstr(), &st) != 0)
return InvalidTime;
return st.st_mtime;
return st.st_mtim;
}
String get_kak_binary_path()

View File

@ -52,7 +52,17 @@ Vector<String> list_files(StringView directory);
void make_directory(StringView dir);
time_t get_fs_timestamp(StringView filename);
timespec get_fs_timestamp(StringView filename);
constexpr bool operator==(const timespec& lhs, const timespec& rhs)
{
return lhs.tv_sec == rhs.tv_sec and lhs.tv_nsec == rhs.tv_nsec;
}
constexpr bool operator!=(const timespec& lhs, const timespec& rhs)
{
return not (lhs == rhs);
}
CandidateList complete_filename(StringView prefix, const Regex& ignore_regex,
ByteCount cursor_pos = -1);