return 0;
}
-int stktable_alloc_data_type(struct stktable *t, int type, const char *sa);
+int stktable_alloc_data_type(struct stktable *t, int type, const char *sa, const char *sa2);
/* return pointer for data type <type> in sticky session <ts> of table <t>, all
* of which must exist (otherwise use stktable_data_ptr() if unsure).
return __stktable_data_ptr(t, ts, type);
}
+/* return pointer on the element of index <idx> from the array data type <type>
+ * in sticky session <ts> of table <t>, or NULL if either <ts> is NULL
+ * or this element is not stored because this type is not stored or
+ * requested index is greater than the number of elements of the array.
+ * Note: this function is also usable on non array types, they are
+ * considered as array of size 1, so a call with <idx> at 0
+ * as the same behavior than 'stktable_data_ptr'.
+ */
+static inline void *stktable_data_ptr_idx(struct stktable *t, struct stksess *ts, int type, unsigned int idx)
+{
+ if (type >= STKTABLE_DATA_TYPES)
+ return NULL;
+
+ if (!t->data_ofs[type]) /* type not stored */
+ return NULL;
+
+ if (!ts)
+ return NULL;
+
+ if (t->data_nbelem[type] <= idx)
+ return NULL;
+
+ return __stktable_data_ptr(t, ts, type) + idx*stktable_type_size(stktable_data_types[type].std_type);
+}
+
/* kill an entry if it's expired and its ref_cnt is zero */
static inline int __stksess_kill_if_expired(struct stktable *t, struct stksess *ts)
{
else {
ha_free(&mrule->table.name);
mrule->table.t = target;
- stktable_alloc_data_type(target, STKTABLE_DT_SERVER_ID, NULL);
- stktable_alloc_data_type(target, STKTABLE_DT_SERVER_KEY, NULL);
+ stktable_alloc_data_type(target, STKTABLE_DT_SERVER_ID, NULL, NULL);
+ stktable_alloc_data_type(target, STKTABLE_DT_SERVER_KEY, NULL, NULL);
if (!in_proxies_list(target->proxies_list, curproxy)) {
curproxy->next_stkt_ref = target->proxies_list;
target->proxies_list = curproxy;
else {
ha_free(&mrule->table.name);
mrule->table.t = target;
- stktable_alloc_data_type(target, STKTABLE_DT_SERVER_ID, NULL);
- stktable_alloc_data_type(target, STKTABLE_DT_SERVER_KEY, NULL);
+ stktable_alloc_data_type(target, STKTABLE_DT_SERVER_ID, NULL, NULL);
+ stktable_alloc_data_type(target, STKTABLE_DT_SERVER_KEY, NULL, NULL);
if (!in_proxies_list(target->proxies_list, curproxy)) {
curproxy->next_stkt_ref = target->proxies_list;
target->proxies_list = curproxy;
return 1;
}
-/* reserve some space for data type <type>, and associate argument at <sa> if
- * not NULL. Returns PE_NONE (0) if OK or an error code among :
+/* reserve some space for data type <type>, there is 2 optionnals
+ * argument at <sa> and <sa2> to configure this data type and
+ * they can be NULL if unused for a given type.
+ * Returns PE_NONE (0) if OK or an error code among :
* - PE_ENUM_OOR if <type> does not exist
* - PE_EXIST if <type> is already registered
- * - PE_ARG_NOT_USE if <sa> was provided but not expected
- * - PE_ARG_MISSING if <sa> was expected but not provided
+ * - PE_ARG_NOT_USE if <sa>/<sa2> was provided but not expected
+ * - PE_ARG_MISSING if <sa>/<sa2> was expected but not provided
+ * - PE_ARG_VALUE_OOR if type is an array and <sa> it out of array size range.
*/
-int stktable_alloc_data_type(struct stktable *t, int type, const char *sa)
+int stktable_alloc_data_type(struct stktable *t, int type, const char *sa, const char *sa2)
+
{
if (type >= STKTABLE_DATA_TYPES)
return PE_ENUM_OOR;
/* already allocated */
return PE_EXIST;
+ t->data_nbelem[type] = 1;
+ if (stktable_data_types[type].is_array) {
+ /* arrays take their element count on first argument */
+ if (!sa)
+ return PE_ARG_MISSING;
+ t->data_nbelem[type] = atoi(sa);
+ if (!t->data_nbelem[type] || (t->data_nbelem[type] > STKTABLE_MAX_DT_ARRAY_SIZE))
+ return PE_ARG_VALUE_OOR;
+ sa = sa2;
+ }
+
switch (stktable_data_types[type].arg_type) {
case ARG_T_NONE:
if (sa)
break;
}
- t->data_size += stktable_type_size(stktable_data_types[type].std_type);
+ t->data_size += t->data_nbelem[type] * stktable_type_size(stktable_data_types[type].std_type);
t->data_ofs[type] = -t->data_size;
return PE_NONE;
}
}
else if (strcmp(args[idx], "store") == 0) {
int type, err;
- char *cw, *nw, *sa;
+ char *cw, *nw, *sa, *sa2;
idx++;
nw = args[idx];
/* the "store" keyword supports a comma-separated list */
cw = nw;
sa = NULL; /* store arg */
+ sa2 = NULL;
while (*nw && *nw != ',') {
if (*nw == '(') {
*nw = 0;
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
+ if (*nw == ',') {
+ *nw = '\0';
+ sa2 = nw + 1;
+ }
nw++;
}
*nw = '\0';
goto out;
}
- err = stktable_alloc_data_type(t, type, sa);
+ err = stktable_alloc_data_type(t, type, sa, sa2);
switch (err) {
case PE_NONE: break;
case PE_EXIST:
file, linenum, args[0], cw);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
+ case PE_ARG_VALUE_OOR:
+ ha_alert("parsing [%s:%d] : %s: array size is out of allowed range (1-%d) for store option '%s'.\n",
+ file, linenum, args[0], STKTABLE_MAX_DT_ARRAY_SIZE, cw);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
default:
ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
if (t->data_ofs[dt] == 0)
continue;
+ if (stktable_data_types[dt].is_array) {
+ char tmp[16] = {};
+ const char *name_pfx = stktable_data_types[dt].name;
+ const char *name_sfx = NULL;
+ unsigned int idx = 0;
+ int i = 0;
+
+ /* split name to show index before first _ of the name
+ * for example: 'gpc3_rate' if array name is 'gpc_rate'.
+ */
+ for (i = 0 ; i < (sizeof(tmp) - 1); i++) {
+ if (!name_pfx[i])
+ break;
+ if (name_pfx[i] == '_') {
+ name_pfx = &tmp[0];
+ name_sfx = &stktable_data_types[dt].name[i];
+ break;
+ }
+ tmp[i] = name_pfx[i];
+ }
+
+ ptr = stktable_data_ptr_idx(t, entry, dt, idx);
+ while (ptr) {
+ if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
+ chunk_appendf(msg, " %s%u%s(%u)=", name_pfx, idx, name_sfx ? name_sfx : "", t->data_arg[dt].u);
+ else
+ chunk_appendf(msg, " %s%u%s=", name_pfx, idx, name_sfx ? name_sfx : "");
+ switch (stktable_data_types[dt].std_type) {
+ case STD_T_SINT:
+ chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
+ break;
+ case STD_T_UINT:
+ chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
+ break;
+ case STD_T_ULL:
+ chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
+ break;
+ case STD_T_FRQP:
+ chunk_appendf(msg, "%u",
+ read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
+ t->data_arg[dt].u));
+ break;
+ }
+ ptr = stktable_data_ptr_idx(t, entry, dt, ++idx);
+ }
+ continue;
+ }
if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
chunk_appendf(msg, " %s(%u)=", stktable_data_types[dt].name, t->data_arg[dt].u);
else