diff mbox series

[4/9] libtraceeval: Add traceeval_iterator_remove()

Message ID 20230817222422.118568-5-rostedt@goodmis.org (mailing list archive)
State Superseded
Headers show
Series libtraceeval: Even more updates! | expand

Commit Message

Steven Rostedt Aug. 17, 2023, 10:24 p.m. UTC
From: "Steven Rostedt (Google)" <rostedt@goodmis.org>

Add an API traceeval_iterator_remove() that is safe to call in the
traceeval_iterator_next() loop. Currently, traceeval_remove() can also be
called "safely", but that may change in the future.

The main difference between traceeval_remove() and traceeval_iterator_remove()
is that that traceeval_iterator_remove() will NULL out the entry in the
sort array, and use this in the other iterator functions. If the entry is
NULL, it will not be returned.

Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
---
 include/traceeval-hist.h |  1 +
 src/histograms.c         | 48 ++++++++++++++++++++++++++++++++++++----
 2 files changed, 45 insertions(+), 4 deletions(-)

Comments

Ross Zwisler Aug. 24, 2023, 8:19 p.m. UTC | #1
On Thu, Aug 17, 2023 at 06:24:17PM -0400, Steven Rostedt wrote:
> From: "Steven Rostedt (Google)" <rostedt@goodmis.org>
> 
> Add an API traceeval_iterator_remove() that is safe to call in the
> traceeval_iterator_next() loop. Currently, traceeval_remove() can also be
> called "safely", but that may change in the future.
> 
> The main difference between traceeval_remove() and traceeval_iterator_remove()
> is that that traceeval_iterator_remove() will NULL out the entry in the
> sort array, and use this in the other iterator functions. If the entry is
> NULL, it will not be returned.
> 
> Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
> ---
>  include/traceeval-hist.h |  1 +
>  src/histograms.c         | 48 ++++++++++++++++++++++++++++++++++++----
>  2 files changed, 45 insertions(+), 4 deletions(-)
> 
> diff --git a/include/traceeval-hist.h b/include/traceeval-hist.h
> index d511c9c5f14c..7d67673ce7e5 100644
> --- a/include/traceeval-hist.h
> +++ b/include/traceeval-hist.h
> @@ -190,5 +190,6 @@ int traceeval_iterator_query(struct traceeval_iterator *iter,
>  			     const union traceeval_data **results);
>  struct traceeval_stat *traceeval_iterator_stat(struct traceeval_iterator *iter,
>  					       struct traceeval_type *type);
> +int traceeval_iterator_remove(struct traceeval_iterator *iter);
>  
>  #endif /* __LIBTRACEEVAL_HIST_H__ */
> diff --git a/src/histograms.c b/src/histograms.c
> index fddd0f3587e2..0fbd9e0a353e 100644
> --- a/src/histograms.c
> +++ b/src/histograms.c
> @@ -1305,10 +1305,13 @@ int traceeval_iterator_next(struct traceeval_iterator *iter,
>  		iter->next = 0;
>  	}
>  
> -	if (iter->next >= iter->nr_entries)
> -		return 0;
> +	do {
> +		if (iter->next >= iter->nr_entries)
> +			return 0;
> +
> +		entry = iter->entries[iter->next++];
> +	} while (!entry);
>  
> -	entry = iter->entries[iter->next++];
>  	*keys = entry->keys;
>  	return 1;
>  }
> @@ -1338,6 +1341,9 @@ int traceeval_iterator_query(struct traceeval_iterator *iter,
>  		return 0;
>  
>  	entry = iter->entries[iter->next - 1];
> +	if (!entry)
> +		return 0;
> +
>  	*results = entry->vals;
>  
>  	return 1;
> @@ -1363,5 +1369,39 @@ struct traceeval_stat *traceeval_iterator_stat(struct traceeval_iterator *iter,
>  		return NULL;
>  
>  	entry = iter->entries[iter->next - 1];
> -	return &entry->val_stats[type->index];
> +	return entry ? &entry->val_stats[type->index] : NULL;
> +}
> +
> +/**
> + * traceeval_iterator_remove - remove the current iterator entry
> + * @iter: The iterator to remove the entry from
> + *
> + * This will remove the current entry from the histogram.
> + * This is useful if the current entry should be removed. It will not
> + * affect the traceeval_iterator_next().
> + *
> + * Returns 1 if it successfully removed the entry, 0 if for some reason
> + * there was no "current entry" (called before traceeval_iterator_next()).
> + * or -1 on error.
> + */
> +int traceeval_iterator_remove(struct traceeval_iterator *iter)
> +{
> +	struct traceeval *teval = iter->teval;
> +	struct hash_table *hist = teval->hist;
> +	struct entry *entry;
> +
> +	if (iter->next < 1 || iter->next > iter->nr_entries)
> +		return 0;
> +
> +	entry = iter->entries[iter->next - 1];
> +	if (!entry)
> +		return 0;
> +
> +	hash_remove(hist, &entry->hash);

Are we leaking 'entry' after we've removed it from the hash?

I think we need to call free_entry() in both traceeval_iterator_remove() as
well as traceeval_remove(), just like we do in the loop in
hist_table_release().

> +
> +	/* The entry no longer exists */
> +	iter->entries[iter->next - 1] = NULL;
> +	teval->update_counter++;
> +
> +	return 1;
>  }
> -- 
> 2.40.1
>
Ross Zwisler Aug. 24, 2023, 8:23 p.m. UTC | #2
On Thu, Aug 24, 2023 at 02:19:06PM -0600, Ross Zwisler wrote:
> On Thu, Aug 17, 2023 at 06:24:17PM -0400, Steven Rostedt wrote:
> > From: "Steven Rostedt (Google)" <rostedt@goodmis.org>
> > 
> > Add an API traceeval_iterator_remove() that is safe to call in the
> > traceeval_iterator_next() loop. Currently, traceeval_remove() can also be
> > called "safely", but that may change in the future.
> > 
> > The main difference between traceeval_remove() and traceeval_iterator_remove()
> > is that that traceeval_iterator_remove() will NULL out the entry in the
> > sort array, and use this in the other iterator functions. If the entry is
> > NULL, it will not be returned.
> > 
> > Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
> > ---
> >  include/traceeval-hist.h |  1 +
> >  src/histograms.c         | 48 ++++++++++++++++++++++++++++++++++++----
> >  2 files changed, 45 insertions(+), 4 deletions(-)
> > 
> > diff --git a/include/traceeval-hist.h b/include/traceeval-hist.h
> > index d511c9c5f14c..7d67673ce7e5 100644
> > --- a/include/traceeval-hist.h
> > +++ b/include/traceeval-hist.h
> > @@ -190,5 +190,6 @@ int traceeval_iterator_query(struct traceeval_iterator *iter,
> >  			     const union traceeval_data **results);
> >  struct traceeval_stat *traceeval_iterator_stat(struct traceeval_iterator *iter,
> >  					       struct traceeval_type *type);
> > +int traceeval_iterator_remove(struct traceeval_iterator *iter);
> >  
> >  #endif /* __LIBTRACEEVAL_HIST_H__ */
> > diff --git a/src/histograms.c b/src/histograms.c
> > index fddd0f3587e2..0fbd9e0a353e 100644
> > --- a/src/histograms.c
> > +++ b/src/histograms.c
> > @@ -1305,10 +1305,13 @@ int traceeval_iterator_next(struct traceeval_iterator *iter,
> >  		iter->next = 0;
> >  	}
> >  
> > -	if (iter->next >= iter->nr_entries)
> > -		return 0;
> > +	do {
> > +		if (iter->next >= iter->nr_entries)
> > +			return 0;
> > +
> > +		entry = iter->entries[iter->next++];
> > +	} while (!entry);
> >  
> > -	entry = iter->entries[iter->next++];
> >  	*keys = entry->keys;
> >  	return 1;
> >  }
> > @@ -1338,6 +1341,9 @@ int traceeval_iterator_query(struct traceeval_iterator *iter,
> >  		return 0;
> >  
> >  	entry = iter->entries[iter->next - 1];
> > +	if (!entry)
> > +		return 0;
> > +
> >  	*results = entry->vals;
> >  
> >  	return 1;
> > @@ -1363,5 +1369,39 @@ struct traceeval_stat *traceeval_iterator_stat(struct traceeval_iterator *iter,
> >  		return NULL;
> >  
> >  	entry = iter->entries[iter->next - 1];
> > -	return &entry->val_stats[type->index];
> > +	return entry ? &entry->val_stats[type->index] : NULL;
> > +}
> > +
> > +/**
> > + * traceeval_iterator_remove - remove the current iterator entry
> > + * @iter: The iterator to remove the entry from
> > + *
> > + * This will remove the current entry from the histogram.
> > + * This is useful if the current entry should be removed. It will not
> > + * affect the traceeval_iterator_next().
> > + *
> > + * Returns 1 if it successfully removed the entry, 0 if for some reason
> > + * there was no "current entry" (called before traceeval_iterator_next()).
> > + * or -1 on error.

Nit: we never actually return -1.  Only 1 and 0.

> > + */
> > +int traceeval_iterator_remove(struct traceeval_iterator *iter)
> > +{
> > +	struct traceeval *teval = iter->teval;
> > +	struct hash_table *hist = teval->hist;
> > +	struct entry *entry;
> > +
> > +	if (iter->next < 1 || iter->next > iter->nr_entries)
> > +		return 0;
> > +
> > +	entry = iter->entries[iter->next - 1];
> > +	if (!entry)
> > +		return 0;
> > +
> > +	hash_remove(hist, &entry->hash);
> 
> Are we leaking 'entry' after we've removed it from the hash?
> 
> I think we need to call free_entry() in both traceeval_iterator_remove() as
> well as traceeval_remove(), just like we do in the loop in
> hist_table_release().
> 
> > +
> > +	/* The entry no longer exists */
> > +	iter->entries[iter->next - 1] = NULL;
> > +	teval->update_counter++;
> > +
> > +	return 1;
> >  }
> > -- 
> > 2.40.1
> >
Steven Rostedt Sept. 27, 2023, 9:09 a.m. UTC | #3
On Thu, 24 Aug 2023 14:19:06 -0600
Ross Zwisler <zwisler@google.com> wrote:

> > +int traceeval_iterator_remove(struct traceeval_iterator *iter)
> > +{
> > +	struct traceeval *teval = iter->teval;
> > +	struct hash_table *hist = teval->hist;
> > +	struct entry *entry;
> > +
> > +	if (iter->next < 1 || iter->next > iter->nr_entries)
> > +		return 0;
> > +
> > +	entry = iter->entries[iter->next - 1];
> > +	if (!entry)
> > +		return 0;
> > +
> > +	hash_remove(hist, &entry->hash);  
> 
> Are we leaking 'entry' after we've removed it from the hash?

Yeah, I guess we are. Good catch!

> 
> I think we need to call free_entry() in both traceeval_iterator_remove() as
> well as traceeval_remove(), just like we do in the loop in
> hist_table_release().

Yep, thanks Ross!

-- Steve

> 
> > +
> > +	/* The entry no longer exists */
> > +	iter->entries[iter->next - 1] = NULL;
> > +	teval->update_counter++;
> > +
> > +	return 1;
> >  }
> > -- 
> > 2.40.1
> >
Steven Rostedt Sept. 27, 2023, 9:51 a.m. UTC | #4
On Thu, 24 Aug 2023 14:23:24 -0600
Ross Zwisler <zwisler@google.com> wrote:

> > > + * Returns 1 if it successfully removed the entry, 0 if for some reason
> > > + * there was no "current entry" (called before traceeval_iterator_next()).
> > > + * or -1 on error.  
> 
> Nit: we never actually return -1.  Only 1 and 0.
> 

Yeah, I usually just throw the -1 in there in case I want to add more
error checking, but since 1 is success, I'll just make it 1 and 0
anyway.

Thanks,

-- Steve
diff mbox series

Patch

diff --git a/include/traceeval-hist.h b/include/traceeval-hist.h
index d511c9c5f14c..7d67673ce7e5 100644
--- a/include/traceeval-hist.h
+++ b/include/traceeval-hist.h
@@ -190,5 +190,6 @@  int traceeval_iterator_query(struct traceeval_iterator *iter,
 			     const union traceeval_data **results);
 struct traceeval_stat *traceeval_iterator_stat(struct traceeval_iterator *iter,
 					       struct traceeval_type *type);
+int traceeval_iterator_remove(struct traceeval_iterator *iter);
 
 #endif /* __LIBTRACEEVAL_HIST_H__ */
diff --git a/src/histograms.c b/src/histograms.c
index fddd0f3587e2..0fbd9e0a353e 100644
--- a/src/histograms.c
+++ b/src/histograms.c
@@ -1305,10 +1305,13 @@  int traceeval_iterator_next(struct traceeval_iterator *iter,
 		iter->next = 0;
 	}
 
-	if (iter->next >= iter->nr_entries)
-		return 0;
+	do {
+		if (iter->next >= iter->nr_entries)
+			return 0;
+
+		entry = iter->entries[iter->next++];
+	} while (!entry);
 
-	entry = iter->entries[iter->next++];
 	*keys = entry->keys;
 	return 1;
 }
@@ -1338,6 +1341,9 @@  int traceeval_iterator_query(struct traceeval_iterator *iter,
 		return 0;
 
 	entry = iter->entries[iter->next - 1];
+	if (!entry)
+		return 0;
+
 	*results = entry->vals;
 
 	return 1;
@@ -1363,5 +1369,39 @@  struct traceeval_stat *traceeval_iterator_stat(struct traceeval_iterator *iter,
 		return NULL;
 
 	entry = iter->entries[iter->next - 1];
-	return &entry->val_stats[type->index];
+	return entry ? &entry->val_stats[type->index] : NULL;
+}
+
+/**
+ * traceeval_iterator_remove - remove the current iterator entry
+ * @iter: The iterator to remove the entry from
+ *
+ * This will remove the current entry from the histogram.
+ * This is useful if the current entry should be removed. It will not
+ * affect the traceeval_iterator_next().
+ *
+ * Returns 1 if it successfully removed the entry, 0 if for some reason
+ * there was no "current entry" (called before traceeval_iterator_next()).
+ * or -1 on error.
+ */
+int traceeval_iterator_remove(struct traceeval_iterator *iter)
+{
+	struct traceeval *teval = iter->teval;
+	struct hash_table *hist = teval->hist;
+	struct entry *entry;
+
+	if (iter->next < 1 || iter->next > iter->nr_entries)
+		return 0;
+
+	entry = iter->entries[iter->next - 1];
+	if (!entry)
+		return 0;
+
+	hash_remove(hist, &entry->hash);
+
+	/* The entry no longer exists */
+	iter->entries[iter->next - 1] = NULL;
+	teval->update_counter++;
+
+	return 1;
 }