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, Buffer::Buffer(String name, Flags flags, BufferLines lines,
time_t fs_timestamp) timespec fs_timestamp)
: Scope(GlobalScope::instance()), : Scope(GlobalScope::instance()),
m_name((flags & Flags::File) ? real_path(parse_filename(name)) : std::move(name)), 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), 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()) if (lines.empty())
lines.emplace_back(StringData::create("\n")); lines.emplace_back(StringData::create("\n"));
@ -531,13 +531,13 @@ ByteCoord Buffer::char_prev(ByteCoord coord) const
return coord; return coord;
} }
time_t Buffer::fs_timestamp() const timespec Buffer::fs_timestamp() const
{ {
kak_assert(m_flags & Flags::File); kak_assert(m_flags & Flags::File);
return m_fs_timestamp; 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); kak_assert(m_flags & Flags::File);
m_fs_timestamp = ts; m_fs_timestamp = ts;

View File

@ -14,7 +14,7 @@ namespace Kakoune
class Buffer; class Buffer;
constexpr time_t InvalidTime = 0; constexpr timespec InvalidTime = { -1, -1 };
// A BufferIterator permits to iterate over the characters of a buffer // A BufferIterator permits to iterate over the characters of a buffer
class BufferIterator class BufferIterator
@ -79,7 +79,7 @@ public:
}; };
Buffer(String name, Flags flags, BufferLines lines = {}, Buffer(String name, Flags flags, BufferLines lines = {},
time_t fs_timestamp = InvalidTime); timespec fs_timestamp = InvalidTime);
Buffer(const Buffer&) = delete; Buffer(const Buffer&) = delete;
Buffer& operator= (const Buffer&) = delete; Buffer& operator= (const Buffer&) = delete;
~Buffer(); ~Buffer();
@ -93,8 +93,8 @@ public:
BufferIterator erase(BufferIterator begin, BufferIterator end); BufferIterator erase(BufferIterator begin, BufferIterator end);
size_t timestamp() const; size_t timestamp() const;
time_t fs_timestamp() const; timespec fs_timestamp() const;
void set_fs_timestamp(time_t ts); void set_fs_timestamp(timespec ts);
void commit_undo_group(); void commit_undo_group();
bool undo(); bool undo();
@ -152,7 +152,7 @@ public:
void run_hook_in_own_context(StringView hook_name, StringView param); 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; void check_invariant() const;
@ -213,7 +213,7 @@ private:
Vector<Change, MemoryDomain::BufferMeta> m_changes; 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 // Values are just data holding by the buffer, they are not part of its
// observable state // 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* 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; bool bom = false, crlf = false;
@ -98,7 +98,7 @@ Buffer* create_fifo_buffer(String name, int fd, bool scroll)
if (buffer) if (buffer)
{ {
buffer->flags() |= Buffer::Flags::NoUndo; buffer->flags() |= Buffer::Flags::NoUndo;
buffer->reload({"\n"_ss}, 0); buffer->reload({"\n"_ss}, InvalidTime);
} }
else else
buffer = new Buffer(std::move(name), Buffer::Flags::Fifo | Buffer::Flags::NoUndo); 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* create_buffer_from_data(StringView data, StringView name,
Buffer::Flags flags, Buffer::Flags flags,
time_t fs_timestamp = InvalidTime); timespec fs_timestamp = InvalidTime);
void write_to_debug_buffer(StringView str); void write_to_debug_buffer(StringView str);

View File

@ -246,7 +246,7 @@ void Client::check_if_buffer_needs_reloading()
return; return;
const String& filename = buffer.name(); 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()) if (ts == InvalidTime or ts == buffer.fs_timestamp())
return; return;
if (reload == Ask) 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"); 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 if (S_ISFIFO(st.st_mode)) // Do not try to read fifos, use them as write only
return create_buffer_from_data({}, real_filename, 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); 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); }); auto unmap = on_scope_end([&]{ munmap((void*)data, st.st_size); });
return create_buffer_from_data({data, data + st.st_size}, real_filename, 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) static void write(int fd, StringView data)
@ -423,11 +423,11 @@ Vector<String> complete_command(StringView prefix, ByteCount cursor_pos)
return res; return res;
} }
typedef decltype(stat::st_mtime) TimeSpec; typedef decltype(stat::st_mtim) TimeSpec;
struct CommandCache struct CommandCache
{ {
TimeSpec mtime = {}; TimeSpec mtim = {};
Vector<String> commands; Vector<String> commands;
}; };
static UnorderedMap<String, CommandCache, MemoryDomain::Commands> command_cache; static UnorderedMap<String, CommandCache, MemoryDomain::Commands> command_cache;
@ -442,7 +442,7 @@ Vector<String> complete_command(StringView prefix, ByteCount cursor_pos)
continue; continue;
auto& cache = command_cache[dirname]; 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) { auto filter = [&](const dirent& entry) {
struct stat st; struct stat st;
@ -457,7 +457,7 @@ Vector<String> complete_command(StringView prefix, ByteCount cursor_pos)
}; };
cache.commands = list_files("", dirname, filter); 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) for (auto& cmd : cache.commands)
{ {
@ -471,12 +471,12 @@ Vector<String> complete_command(StringView prefix, ByteCount cursor_pos)
return res; return res;
} }
time_t get_fs_timestamp(StringView filename) timespec get_fs_timestamp(StringView filename)
{ {
struct stat st; struct stat st;
if (stat(filename.zstr(), &st) != 0) if (stat(filename.zstr(), &st) != 0)
return InvalidTime; return InvalidTime;
return st.st_mtime; return st.st_mtim;
} }
String get_kak_binary_path() String get_kak_binary_path()

View File

@ -52,7 +52,17 @@ Vector<String> list_files(StringView directory);
void make_directory(StringView dir); 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, CandidateList complete_filename(StringView prefix, const Regex& ignore_regex,
ByteCount cursor_pos = -1); ByteCount cursor_pos = -1);