On Sat, Jun 10, 2017 at 3:40 PM, Ben Peart <[email protected]> wrote:
> +int read_fsmonitor_extension(struct index_state *istate, const void *data,
> + unsigned long sz)
> +{
> + const char *index = data;
> + uint32_t hdr_version;
> + uint32_t ewah_size;
> + int ret;
> +
> + if (sz < sizeof(uint32_t) + sizeof(uint64_t) + sizeof(uint32_t))
> + return error("corrupt fsmonitor extension (too short)");
> +
> + hdr_version = get_be32(index);
Here we use get_be32(), ...
> + index += sizeof(uint32_t);
> + if (hdr_version != INDEX_EXTENSION_VERSION)
> + return error("bad fsmonitor version %d", hdr_version);
> +
> + istate->fsmonitor_last_update = get_be64(index);
...get_be64(), ...
> + index += sizeof(uint64_t);
> +
> + ewah_size = get_be32(index);
... and get_be32 again, ...
> + index += sizeof(uint32_t);
> +
> + istate->fsmonitor_dirty = ewah_new();
> + ret = ewah_read_mmap(istate->fsmonitor_dirty, index, ewah_size);
> + if (ret != ewah_size) {
> + ewah_free(istate->fsmonitor_dirty);
> + istate->fsmonitor_dirty = NULL;
> + return error("failed to parse ewah bitmap reading fsmonitor
> index extension");
> + }
> +
> + return 0;
> +}
> +
> +void write_fsmonitor_extension(struct strbuf *sb, struct index_state *istate)
> +{
> + uint32_t hdr_version;
> + uint64_t tm;
> + struct ewah_bitmap *bitmap;
> + int i;
> + uint32_t ewah_start;
> + uint32_t ewah_size = 0;
> + int fixup = 0;
> +
> + hdr_version = htonl(INDEX_EXTENSION_VERSION);
... but here we use htonl() instead of put_be32(), ...
> + strbuf_add(sb, &hdr_version, sizeof(uint32_t));
> +
> + tm = htonll((uint64_t)istate->fsmonitor_last_update);
... htonll(), ...
> + strbuf_add(sb, &tm, sizeof(uint64_t));
> + fixup = sb->len;
> + strbuf_add(sb, &ewah_size, sizeof(uint32_t)); /* we'll fix this up
> later */
> +
> + ewah_start = sb->len;
> + bitmap = ewah_new();
> + for (i = 0; i < istate->cache_nr; i++)
> + if (istate->cache[i]->ce_flags & CE_FSMONITOR_DIRTY)
> + ewah_set(bitmap, i);
> + ewah_serialize_strbuf(bitmap, sb);
> + ewah_free(bitmap);
> +
> + /* fix up size field */
> + ewah_size = htonl(sb->len - ewah_start);
... and htonl() again.
It would be more consistent (and perhaps more correct) to use
put_beXX() functions, instead of the htonl() and htonll() functions.
> + memcpy(sb->buf + fixup, &ewah_size, sizeof(uint32_t));
> +}
> +/*
> + * Call the query-fsmonitor hook passing the time of the last saved results.
> + */
> +static int query_fsmonitor(int version, uint64_t last_update, struct strbuf
> *query_result)
> +{
> + struct child_process cp = CHILD_PROCESS_INIT;
> + char ver[64];
> + char date[64];
> + const char *argv[4];
> +
> + if (!(argv[0] = find_hook("query-fsmonitor")))
> + return -1;
> +
> + snprintf(ver, sizeof(version), "%d", version);
> + snprintf(date, sizeof(date), "%" PRIuMAX, (uintmax_t)last_update);
> + argv[1] = ver;
> + argv[2] = date;
> + argv[3] = NULL;
> + cp.argv = argv;
Maybe it would be nicer using the argv_array_pushX() functions.
> + cp.out = -1;
> +
> + return capture_command(&cp, query_result, 1024);
> +}
> +
> +static void mark_file_dirty(struct index_state *istate, const char *name)
> +{
> + struct untracked_cache_dir *dir;
> + int pos;
> +
> + /* find it in the index and mark that entry as dirty */
> + pos = index_name_pos(istate, name, strlen(name));
> + if (pos >= 0) {
> + if (!(istate->cache[pos]->ce_flags & CE_FSMONITOR_DIRTY)) {
> + istate->cache[pos]->ce_flags |= CE_FSMONITOR_DIRTY;
> + istate->cache_changed |= FSMONITOR_CHANGED;
> + }
> + }
> +
> + /*
> + * Find the corresponding directory in the untracked cache
> + * and mark it as invalid
> + */
> + if (!istate->untracked || !istate->untracked->root)
> + return;
> +
> + dir = find_untracked_cache_dir(istate->untracked,
> istate->untracked->root, name);
> + if (dir) {
> + if (dir->valid) {
> + dir->valid = 0;
> + istate->cache_changed |= FSMONITOR_CHANGED;
> + }
> + }
The code above is quite similar as what is in mark_fsmonitor_dirty(),
so I wonder if a refactoring is possible.
> +}
> +
> +void refresh_by_fsmonitor(struct index_state *istate)
> +{
> + static int has_run_once = 0;
> + struct strbuf query_result = STRBUF_INIT;
> + int query_success = 0;
> + size_t bol = 0; /* beginning of line */
> + uint64_t last_update;
> + char *buf, *entry;
> + int i;
> +
> + if (!core_fsmonitor || has_run_once)
> + return;
> + has_run_once = 1;
> +
> + /*
> + * This could be racy so save the date/time now and the hook
> + * should be inclusive to ensure we don't miss potential changes.
> + */
> + last_update = getnanotime();
> +
> + /*
> + * If we have a last update time, call query-monitor for the set of
> + * changes since that time.
> + */
> + if (istate->fsmonitor_last_update) {
> + query_success = !query_fsmonitor(HOOK_INTERFACE_VERSION,
> + istate->fsmonitor_last_update, &query_result);
> + trace_performance_since(last_update, "query-fsmonitor");
> + }
> +
> + if (query_success) {
> + /* Mark all entries returned by the monitor as dirty */
> + buf = entry = query_result.buf;
> + for (i = 0; i < query_result.len; i++) {
> + if (buf[i] != '\0')
> + continue;
> + mark_file_dirty(istate, buf + bol);
It looks like bol is always equal to i here...
> + bol = i + 1;
> + }
> + if (bol < query_result.len)
> + mark_file_dirty(istate, buf + bol);
... and here too. As it is not used below, I wonder if you really need
the bol variable.
> + /* Mark all clean entries up-to-date */
> + for (i = 0; i < istate->cache_nr; i++) {
> + struct cache_entry *ce = istate->cache[i];
> + if (ce_stage(ce) || (ce->ce_flags &
> CE_FSMONITOR_DIRTY))
> + continue;
> + ce_mark_uptodate(ce);
> + }