Skip to content

Commit ef536b8

Browse files
committed
storing client data in tdb and use their given time
1 parent 67247c0 commit ef536b8

File tree

9 files changed

+366
-153
lines changed

9 files changed

+366
-153
lines changed

etc/tempesta_fw.conf

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,3 +1129,39 @@
11291129
# Default:
11301130
# Health monitor is disabled.
11311131
#
1132+
1133+
# TAG: client_db
1134+
#
1135+
# Path to a client database file used as a storage for clients info.
1136+
# The same as cache_db.
1137+
#
1138+
# Default:
1139+
# client_db /opt/tempesta/db/client.tdb;
1140+
#
1141+
1142+
# TAG: client_tbl_size
1143+
#
1144+
# Size of client drop table.
1145+
#
1146+
# Syntax:
1147+
# client_tbl_size SIZE
1148+
#
1149+
# Default:
1150+
# client_tbl_size 16777216; # 16MB
1151+
#
1152+
1153+
# TAG: client_lifetime
1154+
#
1155+
# Client life time in seconds. Life time of client accounting data after last
1156+
# client connection was closed. The accounting data is used for Frang limits.
1157+
# Zero value means unlimited life time.
1158+
#
1159+
# Syntax:
1160+
# client_lifetime NUM;
1161+
#
1162+
# Example:
1163+
# client_lifetime 3600;
1164+
#
1165+
# Default:
1166+
# client_lifetime 0;
1167+
#

tempesta_db/core/htrie.c

Lines changed: 100 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -806,6 +806,28 @@ tdb_htrie_lookup(TdbHdr *dbh, unsigned long key)
806806
return TDB_PTR(dbh, o);
807807
}
808808

809+
#define TDB_HTRIE_FOREACH_REC(dbh, b_tmp, b, r, body) \
810+
read_lock_bh(&(*b)->lock); \
811+
do { \
812+
r = TDB_HTRIE_BCKT_1ST_REC(*b); \
813+
do { \
814+
size_t rlen = sizeof(*r) + \
815+
TDB_HTRIE_RBODYLEN(dbh, r); \
816+
rlen = TDB_HTRIE_RALIGN(rlen); \
817+
if ((char *)r + rlen - (char *)*b \
818+
> TDB_HTRIE_MINDREC \
819+
&& r != TDB_HTRIE_BCKT_1ST_REC(*b)) \
820+
break; \
821+
body; \
822+
r = (TdbRec *)((char *)r + rlen); \
823+
} while ((char *)r + sizeof(*r) - (char *)*b \
824+
<= TDB_HTRIE_MINDREC); \
825+
b_tmp = TDB_HTRIE_BUCKET_NEXT(dbh, *b); \
826+
if (b_tmp) \
827+
read_lock_bh(&b_tmp->lock); \
828+
read_unlock_bh(&(*b)->lock); \
829+
*b = b_tmp; \
830+
} while (*b)
809831
/**
810832
* Iterate over all records in collision chain with locked buckets.
811833
* Buckets are inspected according to following rules:
@@ -821,29 +843,11 @@ tdb_htrie_bscan_for_rec(TdbHdr *dbh, TdbBucket **b, unsigned long key)
821843
TdbBucket *b_tmp;
822844
TdbRec *r;
823845

824-
read_lock_bh(&(*b)->lock);
825-
826-
do {
827-
r = TDB_HTRIE_BCKT_1ST_REC(*b);
828-
do {
829-
size_t rlen = sizeof(*r) + TDB_HTRIE_RBODYLEN(dbh, r);
830-
rlen = TDB_HTRIE_RALIGN(rlen);
831-
if ((char *)r + rlen - (char *)*b > TDB_HTRIE_MINDREC
832-
&& r != TDB_HTRIE_BCKT_1ST_REC(*b))
833-
break;
834-
if (tdb_live_rec(dbh, r) && r->key == key)
835-
/* Unlock the bucket by tdb_rec_put(). */
836-
return r;
837-
r = (TdbRec *)((char *)r + rlen);
838-
} while ((char *)r + sizeof(*r) - (char *)*b
839-
<= TDB_HTRIE_MINDREC);
840-
841-
b_tmp = TDB_HTRIE_BUCKET_NEXT(dbh, *b);
842-
if (b_tmp)
843-
read_lock_bh(&b_tmp->lock);
844-
read_unlock_bh(&(*b)->lock);
845-
*b = b_tmp;
846-
} while (*b);
846+
TDB_HTRIE_FOREACH_REC(dbh, b_tmp, b, r, {
847+
if (tdb_live_rec(dbh, r) && r->key == key)
848+
/* Unlock the bucket by tdb_rec_put(). */
849+
return r;
850+
});
847851

848852
return NULL;
849853
}
@@ -931,3 +935,76 @@ tdb_htrie_exit(TdbHdr *dbh)
931935
{
932936
free_percpu(dbh->pcpu);
933937
}
938+
939+
static int
940+
tdb_htrie_bucket_walk(TdbHdr *dbh, TdbBucket *b, int (*fn)(void *))
941+
{
942+
TdbBucket *b_tmp;
943+
TdbRec *r;
944+
945+
TDB_HTRIE_FOREACH_REC(dbh, b_tmp, &b, r, {
946+
if (tdb_live_rec(dbh, r)) {
947+
int res = fn(r->data);
948+
if (unlikely(res)) {
949+
read_unlock_bh(&b->lock);
950+
return res;
951+
}
952+
}
953+
});
954+
955+
return 0;
956+
}
957+
958+
static int
959+
tdb_htrie_node_visit(TdbHdr *dbh, TdbHtrieNode *node, int (*fn)(void *))
960+
{
961+
int bits;
962+
int res;
963+
964+
for (bits = 0; bits < TDB_HTRIE_FANOUT; ++bits) {
965+
unsigned long o;
966+
967+
BUG_ON(TDB_HTRIE_RESOLVED(bits));
968+
969+
o = node->shifts[bits];
970+
971+
if (likely(!o))
972+
continue;
973+
974+
BUG_ON(TDB_DI2O(o & ~TDB_HTRIE_DBIT) < TDB_HDR_SZ(dbh) + sizeof(TdbExt)
975+
|| TDB_DI2O(o & ~TDB_HTRIE_DBIT) > dbh->dbsz);
976+
977+
if (o & TDB_HTRIE_DBIT) {
978+
TdbBucket *b;
979+
980+
/* We're at a data pointer - resolve it. */
981+
o ^= TDB_HTRIE_DBIT;
982+
BUG_ON(!o);
983+
984+
b = (TdbBucket *)TDB_PTR(dbh, TDB_DI2O(o));
985+
res = tdb_htrie_bucket_walk(dbh, b, fn);
986+
if (unlikely(res))
987+
return res;
988+
} else {
989+
/*
990+
* The recursion depth being hard-limited.
991+
* The function has the deepest nesting 16 and uses only
992+
* about 16 bytes of stack.
993+
*/
994+
res = tdb_htrie_node_visit(dbh, TDB_PTR(dbh,
995+
TDB_II2O(o)), fn);
996+
if (unlikely(res))
997+
return res;
998+
}
999+
}
1000+
1001+
return 0;
1002+
}
1003+
1004+
int
1005+
tdb_htrie_walk(TdbHdr *dbh, int (*fn)(void *))
1006+
{
1007+
TdbHtrieNode *node = TDB_HTRIE_ROOT(dbh);
1008+
1009+
return tdb_htrie_node_visit(dbh, node, fn);
1010+
}

tempesta_db/core/htrie.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,5 +140,6 @@ TdbRec *tdb_htrie_next_rec(TdbHdr *dbh, TdbRec *r, TdbBucket **b,
140140
unsigned long key);
141141
TdbHdr *tdb_htrie_init(void *p, size_t db_size, unsigned int rec_len);
142142
void tdb_htrie_exit(TdbHdr *dbh);
143+
int tdb_htrie_walk(TdbHdr *dbh, int (*fn)(void *));
143144

144145
#endif /* __HTRIE_H__ */

tempesta_db/core/main.c

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,15 @@
2828
#include "table.h"
2929
#include "tdb_if.h"
3030

31-
#define TDB_VERSION "0.1.16"
31+
#define TDB_VERSION "0.1.17"
3232

3333
MODULE_AUTHOR("Tempesta Technologies");
3434
MODULE_DESCRIPTION("Tempesta DB");
3535
MODULE_VERSION(TDB_VERSION);
3636
MODULE_LICENSE("GPL");
3737

38+
static DEFINE_SPINLOCK(get_alloc_lock);
39+
3840
/**
3941
* Create TDB entry and copy @len contiguous bytes from @data to the entry.
4042
*/
@@ -52,6 +54,7 @@ EXPORT_SYMBOL(tdb_entry_create);
5254

5355
/**
5456
* Create TDB entry to store @len bytes.
57+
* TODO #515 function must holds a lock upon return
5558
*/
5659
TdbRec *
5760
tdb_entry_alloc(TDB *db, unsigned long key, size_t *len)
@@ -222,6 +225,72 @@ tdb_get_db(const char *path, int node)
222225
return tdb_get(db);
223226
}
224227

228+
/**
229+
* Lookup and get a record if the record is found or create TDB entry to store
230+
* @len bytes. If record exist then since we don't copy returned records,
231+
* we have to lock the memory location where the record is placed and
232+
* the user must call tdb_rec_put() when finish with the record.
233+
*
234+
* The caller must not call sleeping functions during work with the record.
235+
* Typically there is only one large record per bucket, so the bucket lock
236+
* is exactly the same as to lock the record. While there could be many
237+
* small records in a bucket, so the caller should not perform long jobs
238+
* with small records.
239+
*
240+
* @return pointer to record with acquired bucket lock if the record is
241+
* found and create TDB entry without acquired locks otherwise.
242+
*
243+
* TODO #515 rework the function is lock-free way
244+
*/
245+
TdbRec *
246+
tdb_rec_get_alloc(TDB *db, unsigned long key, size_t *len,
247+
bool (*predicate)(TdbRec *, void *), bool *is_new, void *data)
248+
{
249+
TdbIter iter;
250+
TdbRec *r;
251+
252+
spin_lock(&get_alloc_lock);
253+
254+
*is_new = false;
255+
iter = tdb_rec_get(db, key);
256+
while (!TDB_ITER_BAD(iter)) {
257+
if ((*predicate)(iter.rec, data)) {
258+
spin_unlock(&get_alloc_lock);
259+
return iter.rec;
260+
}
261+
tdb_rec_next(db, &iter);
262+
}
263+
264+
*is_new = true;
265+
r = tdb_entry_alloc(db, key, len);
266+
267+
spin_unlock(&get_alloc_lock);
268+
269+
return r;
270+
}
271+
EXPORT_SYMBOL(tdb_rec_get_alloc);
272+
273+
int
274+
tdb_entry_walk(TDB *db, int (*fn)(void *))
275+
{
276+
return tdb_htrie_walk(db->hdr, fn);
277+
}
278+
EXPORT_SYMBOL(tdb_entry_walk);
279+
280+
void
281+
tdb_rec_get_lock(void *rec)
282+
{
283+
TdbBucket *b;
284+
285+
BUG_ON(!rec);
286+
287+
b = (TdbBucket *)((unsigned long)rec & TDB_HTRIE_DMASK);
288+
BUG_ON(!b);
289+
290+
read_lock_bh(&b->lock);
291+
}
292+
EXPORT_SYMBOL(tdb_rec_get_lock);
293+
225294
/**
226295
* Open database file and @return its descriptor.
227296
* If the database is already opened, then returns the handler.

tempesta_db/core/tdb.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,11 @@ TdbIter tdb_rec_get(TDB *db, unsigned long key);
173173
void tdb_rec_next(TDB *db, TdbIter *iter);
174174
void tdb_rec_put(void *rec);
175175
int tdb_info(char *buf, size_t len);
176+
TdbRec *tdb_rec_get_alloc(TDB *db, unsigned long key, size_t *len,
177+
bool (*predicate)(TdbRec *, void *), bool *is_new,
178+
void *data);
179+
int tdb_entry_walk(TDB *db, int (*fn)(void *));
180+
void tdb_rec_get_lock(void *rec);
176181

177182
/* Open/close database handler. */
178183
TDB *tdb_open(const char *path, size_t fsize, unsigned int rec_size, int node);

0 commit comments

Comments
 (0)