* Allocate memory for f_str_t
*/
f_str_t*
-fstralloc (size_t len)
+fstralloc (memory_pool_t *pool, size_t len)
{
- f_str_t *res = malloc (sizeof (f_str_t));
+ f_str_t *res = memory_pool_alloc (pool, sizeof (f_str_t));
if (res == NULL) {
return NULL;
}
- res->begin = malloc (len);
+ res->begin = memory_pool_alloc (pool, len);
if (res->begin == NULL) {
free (res);
return NULL;
* Truncate string to its len
*/
f_str_t*
-fstrtruncate (f_str_t *orig)
+fstrtruncate (memory_pool_t *pool, f_str_t *orig)
{
f_str_t *res;
return orig;
}
- res = fstralloc (orig->len);
+ res = fstralloc (pool, orig->len);
if (res == NULL) {
return NULL;
}
fstrcpy (res, orig);
- fstrfree (orig);
return res;
}
* Enlarge string to new size
*/
f_str_t*
-fstrgrow (f_str_t *orig, size_t newlen)
+fstrgrow (memory_pool_t *pool, f_str_t *orig, size_t newlen)
{
f_str_t *res;
return orig;
}
- res = fstralloc (newlen);
+ res = fstralloc (pool, newlen);
if (res == NULL) {
return NULL;
}
fstrcpy (res, orig);
- fstrfree (orig);
return res;
}
#define FSTRING_H
#include <sys/types.h>
+#include "mem_pool.h"
#define update_buf_size(x) (x)->free = (x)->buf->size - ((x)->pos - (x)->buf->begin); (x)->buf->len = (x)->pos - (x)->buf->begin
/*
* Allocate memory for f_str_t
*/
-f_str_t* fstralloc (size_t len);
+f_str_t* fstralloc (memory_pool_t *pool, size_t len);
/*
* Truncate string to its len
*/
-f_str_t* fstrtruncate (f_str_t *orig);
+f_str_t* fstrtruncate (memory_pool_t *pool, f_str_t *orig);
/*
* Enlarge string to new size
*/
-f_str_t* fstrgrow (f_str_t *orig, size_t newlen);
-
-/*
- * Free memory for f_str_t
- */
-#define fstrfree(x) free((x)->begin); free((x))
+f_str_t* fstrgrow (memory_pool_t *pool, f_str_t *orig, size_t newlen);
/*
* Return specified character
#include <sys/types.h>
#include <glib.h>
+#include <string.h>
+#include <stdlib.h>
#include "mem_pool.h"
+#ifdef _THREAD_SAFE
+pthread_mutex_t stat_mtx = PTHREAD_MUTEX_INITIALIZER;
+#define STAT_LOCK() do { pthread_mutex_lock (&stat_mtx); } while (0)
+#define STAT_UNLOCK() do { pthread_mutex_unlock (&stat_mtx); } while (0)
+#else
+#define STAT_LOCK() do {} while (0)
+#define STAT_UNLOCK() do {} while (0)
+#endif
+
+/* Internal statistic */
+static size_t bytes_allocated = 0;
+static size_t chunks_allocated = 0;
+static size_t chunks_freed = 0;
+
static struct _pool_chain *
pool_chain_new (size_t size)
{
chain->len = size;
chain->pos = chain->begin;
chain->next = NULL;
-
+ STAT_LOCK ();
+ chunks_allocated ++;
+ STAT_UNLOCK ();
+
return chain;
}
while (memory_pool_free (cur) < size && cur->next) {
cur = cur->next;
}
- if (cur->next == NULL) {
+ if (cur->next == NULL && memory_pool_free (cur) < size) {
/* Allocate new pool */
- if (cur->len > size) {
+ if (cur->len >= size) {
new = pool_chain_new (cur->len);
}
else {
cur->next = new;
pool->cur_pool = new;
new->pos += size;
+ STAT_LOCK ();
+ bytes_allocated += size;
+ STAT_UNLOCK ();
return new->begin;
}
tmp = cur->pos;
cur->pos += size;
+ STAT_LOCK ();
+ bytes_allocated += size;
+ STAT_UNLOCK ();
return tmp;
}
return NULL;
}
+char *
+memory_pool_strdup (memory_pool_t *pool, const char *src)
+{
+ size_t len;
+ char *newstr;
+
+ if (src == NULL) {
+ return NULL;
+ }
+
+ len = strlen (src);
+ newstr = memory_pool_alloc (pool, len + 1);
+ memcpy (newstr, src, len + 1);
+ return newstr;
+}
+
void
memory_pool_delete (memory_pool_t *pool)
{
cur = cur->next;
g_free (tmp->begin);
g_free (tmp);
+ STAT_LOCK ();
+ chunks_freed ++;
+ STAT_UNLOCK ();
}
g_free (pool);
}
+void
+memory_pool_stat (memory_pool_stat_t *st)
+{
+ st->bytes_allocated = bytes_allocated;
+ st->chunks_allocated = chunks_allocated;
+ st->chunks_freed = chunks_freed;
+}
+
/*
* vi:ts=4
*/
struct _pool_chain *first_pool;
} memory_pool_t;
+typedef struct memory_pool_stat_s {
+ size_t bytes_allocated;
+ size_t chunks_allocated;
+ size_t chunks_freed;
+} memory_pool_stat_t;
+
memory_pool_t* memory_pool_new (size_t size);
void* memory_pool_alloc (memory_pool_t* pool, size_t size);
+char* memory_pool_strdup (memory_pool_t* pool, const char *src);
void memory_pool_delete (memory_pool_t* pool);
-#define memory_pool_free(x) ((x)->pos - (x)->begin)
+void memory_pool_stat (memory_pool_stat_t *st);
+
+#define memory_pool_free(x) ((x)->len - ((x)->pos - (x)->begin))
#endif
}
if (*p == '\0') {
msg_info ("redirector_callback: got reply from redirector: '%s' -> '%s'", struri (param->url), c);
- parse_uri (param->url, c);
+ parse_uri (param->url, c, param->task->task_pool);
register_memcached_call (param->url, param->task);
param->task->save.saved ++;
}
/* content-length */
if (strncasecmp (headern, CONTENT_LENGTH_HEADER, sizeof (CONTENT_LENGTH_HEADER) - 1) == 0) {
task->content_length = strtoul (line, &err, 10);
- task->msg = g_malloc (sizeof (f_str_buf_t));
- task->msg->buf = fstralloc (task->content_length);
+ task->msg = memory_pool_alloc (task->task_pool, sizeof (f_str_buf_t));
+ task->msg->buf = fstralloc (task->task_pool, task->content_length);
if (task->msg->buf == NULL) {
msg_err ("read_socket: cannot allocate memory for message buffer");
return -1;
case 'H':
/* helo */
if (strncasecmp (headern, HELO_HEADER, sizeof (HELO_HEADER) - 1) == 0) {
- task->helo = g_strdup (line);
+ task->helo = memory_pool_strdup (task->task_pool, line);
}
else {
msg_info ("parse_header: wrong header: %s", headern);
case 'F':
/* from */
if (strncasecmp (headern, FROM_HEADER, sizeof (FROM_HEADER) - 1) == 0) {
- task->from = g_strdup (line);
+ task->from = memory_pool_strdup (task->task_pool, line);
}
else {
msg_info ("parse_header: wrong header: %s", headern);
case 'R':
/* rcpt */
if (strncasecmp (headern, RCPT_HEADER, sizeof (RCPT_HEADER) - 1) == 0) {
- task->rcpt = g_strdup (line);
+ task->rcpt = memory_pool_strdup (task->task_pool, line);
}
else {
msg_info ("parse_header: wrong header: %s", headern);
rspamd_mem_pool_test_func ()
{
memory_pool_t *pool;
+ memory_pool_stat_t st;
char *tmp, *tmp2;
pool = memory_pool_new (sizeof (TEST_BUF));
g_assert (strncmp (tmp2, TEST2_BUF, sizeof (TEST2_BUF)) == 0);
memory_pool_delete (pool);
+ memory_pool_stat (&st);
+
+ /* Check allocator stat */
+ g_assert (st.bytes_allocated == sizeof (TEST_BUF) * 3);
+ g_assert (st.chunks_allocated == 2);
+ g_assert (st.chunks_freed == 2);
}
html->len = strlen (test_html);
bzero (&task, sizeof (task));
TAILQ_INIT (&task.urls);
+ task.task_pool = memory_pool_new (8192);
g_test_timer_start ();
g_test_message ("Testing text URL regexp parser");
while (!TAILQ_EMPTY (&task.urls)) {
url = TAILQ_FIRST (&task.urls);
TAILQ_REMOVE (&task.urls, url, next);
- g_free (url->string);
- g_free (url);
}
g_assert (i == 39);
while (!TAILQ_EMPTY (&task.urls)) {
url = TAILQ_FIRST (&task.urls);
TAILQ_REMOVE (&task.urls, url, next);
- g_free (url->string);
- g_free (url);
}
g_assert (i == 1);
msg_debug ("Time elapsed: %.2f", g_test_timer_elapsed ());
freshly allocated string will be returned in all cases. */
static char *
-url_escape_1 (const char *s, unsigned char mask, int allow_passthrough)
+url_escape_1 (const char *s, unsigned char mask, int allow_passthrough, memory_pool_t *pool)
{
const char *p1;
char *p2, *newstr;
if (urlchr_test (*p1, mask))
addition += 2; /* Two more characters (hex digits) */
- if (!addition)
- return allow_passthrough ? (char *)s : strdup (s);
+ if (!addition) {
+ if (allow_passthrough) {
+ return (char *)s;
+ }
+ else {
+ return memory_pool_strdup (pool, s);
+ }
+ }
newlen = (p1 - s) + addition;
- newstr = (char *) g_malloc (newlen + 1);
+ newstr = (char *) memory_pool_alloc (pool, newlen + 1);
p1 = s;
p2 = newstr;
string, returning a freshly allocated string. */
char *
-url_escape (const char *s)
+url_escape (const char *s, memory_pool_t *pool)
{
- return url_escape_1 (s, urlchr_unsafe, 0);
+ return url_escape_1 (s, urlchr_unsafe, 0, pool);
}
/* URL-escape the unsafe characters (see urlchr_table) in a given
string. If no characters are unsafe, S is returned. */
static char *
-url_escape_allow_passthrough (const char *s)
+url_escape_allow_passthrough (const char *s, memory_pool_t *pool)
{
- return url_escape_1 (s, urlchr_unsafe, 1);
+ return url_escape_1 (s, urlchr_unsafe, 1, pool);
}
/* Decide whether the char at position P needs to be encoded. (It is
*/
static char *
-reencode_escapes (const char *s)
+reencode_escapes (const char *s, memory_pool_t *pool)
{
const char *p1;
char *newstr, *p2;
if (char_needs_escaping (p1))
++encode_count;
- if (!encode_count)
+ if (!encode_count) {
/* The string is good as it is. */
- return g_strdup (s); /* C const model sucks. */
+ return memory_pool_strdup (pool, s);
+ }
oldlen = p1 - s;
/* Each encoding adds two characters (hex digits). */
newlen = oldlen + 2 * encode_count;
- newstr = g_malloc (newlen + 1);
+ newstr = memory_pool_alloc (pool, newlen + 1);
/* Second pass: copy the string to the destination address, encoding
chars when needed. */
characters. */
static char *
-url_escape_dir (const char *dir)
+url_escape_dir (const char *dir, memory_pool_t *pool)
{
- char *newdir = url_escape_1 (dir, urlchr_unsafe | urlchr_reserved, 1);
+ char *newdir = url_escape_1 (dir, urlchr_unsafe | urlchr_reserved, 1, pool);
if (newdir == dir)
return (char *)dir;
}
enum uri_errno
-parse_uri(struct uri *uri, unsigned char *uristring)
+parse_uri(struct uri *uri, unsigned char *uristring, memory_pool_t *pool)
{
unsigned char *prefix_end, *host_end, *p;
unsigned char *lbracket, *rbracket;
/* Nothing to do for an empty url. */
if (!*uristring) return URI_ERRNO_EMPTY;
- uri->string = reencode_escapes (uristring);
+ uri->string = reencode_escapes (uristring, pool);
msg_debug ("parse_uri: reencoding escapes in original url: '%s'", struri (uri));
uri->protocollen = get_protocol_length (struri (uri));
url_str = g_match_info_fetch (info, 0);
msg_debug ("url_parse_text: extracted string with regexp: '%s'", url_str);
if (url_str != NULL) {
- new = g_malloc (sizeof (struct uri));
+ new = memory_pool_alloc (task->task_pool, sizeof (struct uri));
if (new != NULL) {
- parse_uri (new, url_str);
+ parse_uri (new, url_str, task->task_pool);
TAILQ_INSERT_TAIL (&task->urls, new, next);
}
}
url_str = g_match_info_fetch (info, 1);
msg_debug ("url_parse_html: extracted string with regexp: '%s'", url_str);
if (url_str != NULL) {
- new = g_malloc (sizeof (struct uri));
+ new = memory_pool_alloc (task->task_pool, sizeof (struct uri));
if (new != NULL) {
- parse_uri (new, url_str);
+ parse_uri (new, url_str, task->task_pool);
TAILQ_INSERT_TAIL (&task->urls, new, next);
}
}
#endif
#include <glib.h>
+#include "mem_pool.h"
struct worker_task;
void url_parse_html (struct worker_task *task, GByteArray *part);
void url_parse_text (struct worker_task *task, GByteArray *part);
-enum uri_errno parse_uri(struct uri *uri, unsigned char *uristring);
+enum uri_errno parse_uri(struct uri *uri, unsigned char *uristring, memory_pool_t *pool);
#endif
all: url_extracter
url_extracter: $(OBJECTS) ../url.o ../util.o
- $(CC) $(PTHREAD_LDFLAGS) $(LDFLAGS) $(OBJECTS) ../url.o ../util.o $(LIBS) -o url_extracter
+ $(CC) $(PTHREAD_LDFLAGS) $(LDFLAGS) $(OBJECTS) ../url.o ../util.o ../mem_pool.o $(LIBS) -o url_extracter
clean:
rm -f *.o url_extracter *.core
#define NRCPT_HEADER "Recipient-Number: "
#define RCPT_HEADER "Rcpt: "
+#define TASK_POOL_SIZE 16384
+
const f_str_t CRLF = {
/* begin */"\r\n",
/* len */2,
struct mime_part *part;
if (task) {
- if (task->msg) {
- fstrfree (task->msg->buf);
- free (task->msg);
- }
if (task->message) {
g_object_unref (task->message);
}
- if (task->helo) {
- free (task->helo);
- }
- if (task->from) {
- free (task->from);
- }
- if (task->rcpt) {
- free (task->rcpt);
- }
if (task->memc_ctx) {
memc_close_ctx (task->memc_ctx);
- free (task->memc_ctx);
- }
- if (task->task_pool) {
- memory_pool_delete (task->task_pool);
}
while (!TAILQ_EMPTY (&task->urls)) {
cur = TAILQ_FIRST (&task->urls);
TAILQ_REMOVE (&task->urls, cur, next);
- free (cur->string);
- free (cur);
}
while (!TAILQ_EMPTY (&task->results)) {
res = TAILQ_FIRST (&task->results);
TAILQ_REMOVE (&task->results, res, next);
- free (res);
}
while (!TAILQ_EMPTY (&task->chain_results)) {
chain_res = TAILQ_FIRST (&task->chain_results);
- if (chain_res->marks != NULL) {
- free (chain_res->marks);
- }
TAILQ_REMOVE (&task->chain_results, chain_res, next);
- free (chain_res);
}
while (!TAILQ_EMPTY (&task->parts)) {
g_object_unref (part->type);
g_object_unref (part->content);
TAILQ_REMOVE (&task->parts, part, next);
- free (part);
}
- free (task);
+ memory_pool_delete (task->task_pool);
+ g_free (task);
}
}
if (g_mime_data_wrapper_write_to_stream (wrapper, part_stream) != -1) {
part_content = g_mime_stream_mem_get_byte_array (GMIME_STREAM_MEM (part_stream));
type = (GMimeContentType *)g_mime_part_get_content_type (GMIME_PART (part));
- mime_part = g_malloc (sizeof (struct mime_part));
+ mime_part = memory_pool_alloc (task->task_pool, sizeof (struct mime_part));
mime_part->type = type;
mime_part->content = part_content;
TAILQ_INSERT_TAIL (&task->parts, mime_part, next);
}
}
while (c_filter != NULL) {
- res = malloc (sizeof (struct filter_result));
+ res = memory_pool_alloc (task->task_pool, sizeof (struct filter_result));
if (res == NULL) {
msg_err ("process_filters: malloc failed, %m");
return -1;
/* Process perl chains */
while (chain != NULL) {
- chain_res = malloc (sizeof (struct chain_result));
+ chain_res = memory_pool_alloc (task->task_pool, sizeof (struct chain_result));
if (chain_res == NULL) {
msg_err ("process_filters: malloc failed, %m");
return -1;
}
i = 0;
chain_res->chain = chain;
- chain_res->marks = malloc (sizeof (int) * chain->scripts_number);
+ chain_res->marks = memory_pool_alloc (task->task_pool, sizeof (int) * chain->scripts_number);
chain_res->result_mark = 0;
if (chain_res->marks == NULL) {
free (chain_res);
/* Skip chain filters first */
continue;
}
- res = malloc (sizeof (struct filter_result));
+ res = memory_pool_alloc (task->task_pool, sizeof (struct filter_result));
if (res == NULL) {
msg_err ("process_filters: malloc failed, %m");
return -1;
{
struct worker_task *task = (struct worker_task *)arg;
ssize_t r;
- char *s, *c;
+ char *s;
switch (task->state) {
case READ_COMMAND:
return;
}
- new_task = malloc (sizeof (struct worker_task));
+ new_task = g_malloc (sizeof (struct worker_task));
if (new_task == NULL) {
msg_err ("accept_socket: cannot allocate memory for task, %m");
return;
TAILQ_INIT (&new_task->urls);
TAILQ_INIT (&new_task->results);
TAILQ_INIT (&new_task->parts);
- new_task->memc_ctx = malloc (sizeof (memcached_ctx_t));
- new_task->task_pool = memory_pool_new (1024);
+ new_task->task_pool = memory_pool_new (TASK_POOL_SIZE);
+ new_task->memc_ctx = memory_pool_alloc (new_task->task_pool, sizeof (memcached_ctx_t));
if (new_task->memc_ctx == NULL) {
msg_err ("accept_socket: cannot allocate memory for memcached ctx, %m");
}