]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Add pair pool allocator
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Mon, 11 Oct 2021 17:53:17 +0000 (12:53 -0500)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Mon, 11 Oct 2021 18:08:04 +0000 (13:08 -0500)
Can save two mallocs for unknown attributes

src/lib/util/pair.c
src/lib/util/pair.h

index cce5ef44c20b839d6d7561a5c66a8598abead886..9ab895757826f5d52c1a1ef7eb99840eeb588b58 100644 (file)
@@ -103,6 +103,21 @@ fr_pair_list_t *fr_pair_list_alloc(TALLOC_CTX *ctx)
        return pl;
 }
 
+/** Initialise fields in an fr_pair_t without assigning a da
+ *
+ * @note Internal use by the allocation functions only.
+ */
+static inline CC_HINT(always_inline) void pair_init_null(fr_pair_t *vp)
+{
+       fr_dlist_entry_init(&vp->order_entry);
+
+       /*
+        *      Legacy cruft
+        */
+       vp->op = T_OP_EQ;
+       vp->type = VT_NONE;
+}
+
 /** Dynamically allocate a new attribute with no #fr_dict_attr_t assigned
  *
  * This is not the function you're looking for (unless you're binding
@@ -125,16 +140,9 @@ fr_pair_t *fr_pair_alloc_null(TALLOC_CTX *ctx)
                fr_strerror_printf("Out of memory");
                return NULL;
        }
-
-       fr_dlist_entry_init(&vp->order_entry);
-
        talloc_set_destructor(vp, _fr_pair_free);
 
-       /*
-        *      Legacy cruft
-        */
-       vp->op = T_OP_EQ;
-       vp->type = VT_NONE;
+       pair_init_null(vp);
 
        return vp;
 }
@@ -144,7 +152,9 @@ fr_pair_t *fr_pair_alloc_null(TALLOC_CTX *ctx)
  * This is intended to allocate root attributes for requests.
  * These roots are special in that they do not necessarily own
  * the child attributes and _MUST NOT_ free them when they
- * themselves are freed.
+ * themselves are freed.  The children are allocated in special
+ * ctxs which may be moved between session state entries and
+ * requests, or may belong to a parent request.
  *
  * @param[in] ctx      to allocate the pair root in.
  * @param[in] da       The root attribute.
@@ -185,13 +195,39 @@ fr_pair_t *fr_pair_root_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
        }
 #endif
 
+       return vp;
+}
+
+/** Continue initialising an fr_pair_t assigning a da
+ *
+ * @note Internal use by the pair allocation functions only.
+ */
+static inline CC_HINT(always_inline) void pair_init_from_da(fr_pair_t *vp, fr_dict_attr_t const *da)
+{
        /*
-        *      Legacy cruft
+        *      If we get passed an unknown da, we need to ensure that
+        *      it's parented by "vp".
         */
-       vp->op = T_OP_EQ;
-       vp->type = VT_NONE;
+       if (da->flags.is_unknown) {
+               fr_dict_attr_t const *unknown;
 
-       return vp;
+               unknown = fr_dict_unknown_afrom_da(vp, da);
+               da = unknown;
+       }
+
+       /*
+        *      Use the 'da' to initialize more fields.
+        */
+       vp->da = da;
+       fr_value_box_init(&vp->data, da->type, da, false);
+
+       switch (da->type) {
+       case FR_TYPE_STRUCTURAL:
+               fr_pair_list_init(&vp->vp_group);
+               break;
+       default:
+               break;
+       }
 }
 
 /** Dynamically allocate a new attribute and assign a #fr_dict_attr_t
@@ -200,6 +236,8 @@ fr_pair_t *fr_pair_root_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
  *
  * @param[in] ctx      for allocated memory, usually a pointer to a #fr_radius_packet_t
  * @param[in] da       Specifies the dictionary attribute to build the #fr_pair_t from.
+ *                     If unknown, will be duplicated, with the memory being bound to
+ *                     the pair.
  * @return
  *     - A new #fr_pair_t.
  *     - NULL if an error occurred.
@@ -215,31 +253,63 @@ fr_pair_t *fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
                return NULL;
        }
 
-       /*
-        *      If we get passed an unknown da, we need to ensure that
-        *      it's parented by "vp".
-        */
-       if (da->flags.is_unknown) {
-               fr_dict_attr_t const *unknown;
+       pair_init_from_da(vp, da);
 
-               unknown = fr_dict_unknown_afrom_da(vp, da);
-               da = unknown;
-       }
+       return vp;
+}
+
+/** Allocate a pooled object that can hold a fr_pair_t any unknown attributes and value buffer
+ *
+ * @param[in] ctx              to allocate the pooled object in.
+ * @param[in] da               If unknown, will be duplicated.
+ * @param[in] value_len                The expected length of the buffer.  +1 will be added if this
+ *                             if a FR_TYPE_STRING attribute.
+ */
+fr_pair_t *fr_pair_afrom_da_with_pool(TALLOC_CTX *ctx, fr_dict_attr_t const *da, size_t value_len)
+{
+       fr_pair_t *vp;
+
+       unsigned int headers = 1;
 
        /*
-        *      Use the 'da' to initialize more fields.
+        *      Dict attributes allocate extensions
+        *      contiguously, so we only need one
+        *      header even though there's a variable
+        *      length name buff.
         */
-       vp->da = da;
-       fr_value_box_init(&vp->data, da->type, da, false);
+       if (da->flags.is_unknown) {
+               headers++;
+               value_len += talloc_array_length(da);   /* accounts for all extensions */
+       }
 
        switch (da->type) {
-       case FR_TYPE_STRUCTURAL:
-               fr_pair_list_init(&vp->vp_group);
+       case FR_TYPE_OCTETS:
+               headers++;
                break;
-       default:
+
+       case FR_TYPE_STRING:
+               headers++;
+               value_len++;
                break;
+
+       default:
+               fr_strerror_printf("Pooled fr_pair_t can only be allocated for "
+                                  "'string' and 'octets' types not '%s'",
+                                  fr_table_str_by_value(fr_value_box_type_table, da->type, "<INVALID>"));
+               return NULL;
+
        }
 
+       vp = talloc_zero_pooled_object(ctx, fr_pair_t, headers, value_len);
+       if (unlikely(!vp)) {
+               fr_strerror_printf("Out of memory");
+               return NULL;
+       }
+       talloc_set_destructor(vp, _fr_pair_free);
+
+       pair_init_null(vp);
+       pair_init_from_da(vp, da);
+
        return vp;
 }
 
index e3f5c28982beae0a03cd921191aec1114d883dce..35949a840752e84f97b67fbab3ee74f46786eadd 100644 (file)
@@ -223,6 +223,9 @@ fr_pair_t   *fr_pair_root_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da) CC_H
 /** @hidecallergraph */
 fr_pair_t      *fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da) CC_HINT(warn_unused_result) CC_HINT(nonnull(2));
 
+fr_pair_t      *fr_pair_afrom_da_with_pool(TALLOC_CTX *ctx, fr_dict_attr_t const *da, size_t value_len)
+               CC_HINT(warn_unused_result) CC_HINT(nonnull(2));
+
 int            fr_pair_reinit_from_da(fr_pair_list_t *list, fr_pair_t *vp, fr_dict_attr_t const *da)
                CC_HINT(nonnull(2, 3));