Jeff King <[email protected]> writes:

> On Thu, May 14, 2015 at 03:25:33PM -0700, Junio C Hamano wrote:
>
>> @@ -90,6 +97,8 @@ static MAYBE_UNUSED elemtype *slabname## _at(struct 
>> slabname *s,   \
>>                                                                      \
>>      if (s->slab_count <= nth_slab) {                                \
>>              int i;                                                  \
>> +            if (!add_if_missing)                                    \
>> +                    return NULL;                                    \
>>              s->slab = xrealloc(s->slab,                             \
>>                                 (nth_slab + 1) * sizeof(*s->slab));  \
>>              stat_ ##slabname## realloc++;                           \
>
> This skips extending the list of slabs if we would go past the nth slab.
> But we don't fill in each slab in the first place. I.e., we may have 10
> slabs, but only s->slab[10] is non-NULL.
>
> A few lines below this, we xcalloc() it if necessary. I think that needs
> to respect add_if_missing, as well.

Yup, thanks.

>
>>  void unuse_commit_buffer(const struct commit *commit, const void *buffer)
>>  {
>> -    struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
>> -    if (v->buffer != buffer)
>> +    struct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit);
>> +    if (v && v->buffer != buffer)
>>              free((void *)buffer);
>>  }
>
> I think you want:
>
>   if (!v || v->buffer != buffer)
>
> here. IOW, we free it only if it is not our cached buffer, and it cannot
> be if we do not have a cached buffer. It may be easier to read by
> flipping the logic:
>
>   if (v && v->buffer == buffer)
>       return; /* it is saved in the cache */
>   free((void *)buffer);
>
> Or some variation on that.

I ended up doing it as a variant of the latter, "free unless we have
v->buffer pointing at it".

Sorry for a long delay.

-- >8 --
Subject: [PATCH] commit-slab: introduce slabname##_peek() function

There is no API to ask "Does this commit have associated data in
slab?".  If an application wants to (1) parse just a few commits at
the beginning of a process, (2) store data for only these commits,
and then (3) start processing many commits, taking into account the
data stored (for a few of them) in the slab, the application would
use slabname##_at() to allocate a space to store data in (2), but
there is no API other than slabname##_at() to use in step (3).  This
allocates and wasts new space for these commits the caller is only
interested in checking if they have data stored in step (2).

Introduce slabname##_peek(), which is similar to slabname##_at() but
returns NULL when there is no data already associated to it in such
a use case.

Helped-by: Jeff King <[email protected]>
Signed-off-by: Junio C Hamano <[email protected]>
---
 commit-slab.h | 34 +++++++++++++++++++++++++++++-----
 commit.c      | 28 ++++++++++++++++++++--------
 2 files changed, 49 insertions(+), 13 deletions(-)

diff --git a/commit-slab.h b/commit-slab.h
index 375c9c7..9d12ce2 100644
--- a/commit-slab.h
+++ b/commit-slab.h
@@ -15,7 +15,13 @@
  * - int *indegree_at(struct indegree *, struct commit *);
  *
  *   This function locates the data associated with the given commit in
- *   the indegree slab, and returns the pointer to it.
+ *   the indegree slab, and returns the pointer to it.  The location to
+ *   store the data is allocated as necessary.
+ *
+ * - int *indegree_peek(struct indegree *, struct commit *);
+ *
+ *   This function is similar to indegree_at(), but it will return NULL
+ *   until a call to indegree_at() was made for the commit.
  *
  * - void init_indegree(struct indegree *);
  *   void init_indegree_with_stride(struct indegree *, int);
@@ -80,8 +86,9 @@ static MAYBE_UNUSED void clear_ ##slabname(struct slabname 
*s)                \
        s->slab = NULL;                                                 \
 }                                                                      \
                                                                        \
-static MAYBE_UNUSED elemtype *slabname## _at(struct slabname *s,       \
-                                      const struct commit *c)          \
+static MAYBE_UNUSED elemtype *slabname## _at_peek(struct slabname *s,  \
+                                                 const struct commit *c, \
+                                                 int add_if_missing)   \
 {                                                                      \
        int nth_slab, nth_slot;                                         \
                                                                        \
@@ -90,6 +97,8 @@ static MAYBE_UNUSED elemtype *slabname## _at(struct slabname 
*s,      \
                                                                        \
        if (s->slab_count <= nth_slab) {                                \
                int i;                                                  \
+               if (!add_if_missing)                                    \
+                       return NULL;                                    \
                s->slab = xrealloc(s->slab,                             \
                                   (nth_slab + 1) * sizeof(*s->slab));  \
                stat_ ##slabname## realloc++;                           \
@@ -97,10 +106,25 @@ static MAYBE_UNUSED elemtype *slabname## _at(struct 
slabname *s,   \
                        s->slab[i] = NULL;                              \
                s->slab_count = nth_slab + 1;                           \
        }                                                               \
-       if (!s->slab[nth_slab])                                         \
+       if (!s->slab[nth_slab]) {                                       \
+               if (!add_if_missing)                                    \
+                       return NULL;                                    \
                s->slab[nth_slab] = xcalloc(s->slab_size,               \
                                            sizeof(**s->slab) * s->stride);     
        \
-       return &s->slab[nth_slab][nth_slot * s->stride];                        
        \
+       }                                                               \
+       return &s->slab[nth_slab][nth_slot * s->stride];                \
+}                                                                      \
+                                                                       \
+static MAYBE_UNUSED elemtype *slabname## _at(struct slabname *s,       \
+                                            const struct commit *c)    \
+{                                                                      \
+       return slabname##_at_peek(s, c, 1);                             \
+}                                                                      \
+                                                                       \
+static MAYBE_UNUSED elemtype *slabname## _peek(struct slabname *s,     \
+                                            const struct commit *c)    \
+{                                                                      \
+       return slabname##_at_peek(s, c, 0);                             \
 }                                                                      \
                                                                        \
 static int stat_ ##slabname## realloc
diff --git a/commit.c b/commit.c
index 65179f9..5fb9496 100644
--- a/commit.c
+++ b/commit.c
@@ -244,7 +244,12 @@ void set_commit_buffer(struct commit *commit, void 
*buffer, unsigned long size)
 
 const void *get_cached_commit_buffer(const struct commit *commit, unsigned 
long *sizep)
 {
-       struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
+       struct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit);
+       if (!v) {
+               if (sizep)
+                       *sizep = 0;
+               return NULL;
+       }
        if (sizep)
                *sizep = v->size;
        return v->buffer;
@@ -271,24 +276,31 @@ const void *get_commit_buffer(const struct commit 
*commit, unsigned long *sizep)
 
 void unuse_commit_buffer(const struct commit *commit, const void *buffer)
 {
-       struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
-       if (v->buffer != buffer)
+       struct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit);
+       if (!(v && v->buffer == buffer))
                free((void *)buffer);
 }
 
 void free_commit_buffer(struct commit *commit)
 {
-       struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
-       free(v->buffer);
-       v->buffer = NULL;
-       v->size = 0;
+       struct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit);
+       if (v) {
+               free(v->buffer);
+               v->buffer = NULL;
+               v->size = 0;
+       }
 }
 
 const void *detach_commit_buffer(struct commit *commit, unsigned long *sizep)
 {
-       struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
+       struct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit);
        void *ret;
 
+       if (!v) {
+               if (sizep)
+                       *sizep = 0;
+               return NULL;
+       }
        ret = v->buffer;
        if (sizep)
                *sizep = v->size;
-- 
2.4.1-449-g1f6c7df

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to