Compare commits
14 commits
Author | SHA1 | Date | |
---|---|---|---|
|
7251740668 | ||
|
e09667818e | ||
|
576d568c16 | ||
|
2dc8cc1533 | ||
|
ae191a1d75 | ||
|
60376804b0 | ||
|
257ced4717 | ||
|
985c8593dd | ||
|
7e08440d0c | ||
|
3041469007 | ||
|
7e545159a0 | ||
|
e401364869 | ||
|
03448d72cf | ||
|
fd9388437e |
11 changed files with 175 additions and 74 deletions
|
@ -3,6 +3,11 @@
|
|||
by Yo-An Lin <yoanlin93@gmail.com>
|
||||
|
||||
|
||||
### 2.0 - Wed Nov 11 11:08:22 2015
|
||||
|
||||
|
||||
|
||||
|
||||
### 1.3.3 - Sat Jun 28 00:53:48 2014
|
||||
|
||||
- Fix graphviz generator.
|
||||
|
|
11
bench.html
11
bench.html
|
@ -150,12 +150,17 @@
|
|||
|
||||
var lines = data.split(/\n/);
|
||||
|
||||
// keep window size to 30 records
|
||||
lines.splice(-30);
|
||||
lines = lines.splice(lines.length - 30);
|
||||
// keep window size to 60 records
|
||||
lines = lines.splice(-60);
|
||||
|
||||
$(lines).each(function(i,line) {
|
||||
if (line == "") {
|
||||
return;
|
||||
}
|
||||
var columns = line.split(/,/);
|
||||
if (columns.length == 0) {
|
||||
return;
|
||||
}
|
||||
var a;
|
||||
a = parseInt(columns[1]);
|
||||
options.series[0].data.push(a || 0);
|
||||
|
|
|
@ -626,3 +626,19 @@
|
|||
1447156411,13229275.90,5858750.37,66576.25,2523350.73
|
||||
1447156432,13556025.90,5873947.56,62601.55,2487130.01
|
||||
1447156745,13744909.39,5913103.69,66576.25,2551782.92
|
||||
1447158285,11638128.71,5241775.30,71089.90,2321077.83
|
||||
1447158396,13539837.29,5874704.47,47662.55,2533571.93
|
||||
1447158415,14054879.53,5952300.47,41527.76,2571669.83
|
||||
1447210457,13616841.50,5604087.24,83886.08,2458628.97
|
||||
1447210807,14529897.99,5833087.33,77672.30,1845729.06
|
||||
1447210834,14016924.69,5806227.80,66576.25,1715107.19
|
||||
1447211104,14738120.40,5873312.56,58254.22,2092537.05
|
||||
1447211128,14875503.82,5649431.95,27776.85,2033045.40
|
||||
1447211244,15335902.86,6019829.26,77672.30,1842297.15
|
||||
1447211259,14365504.46,5812325.12,91180.52,1965977.09
|
||||
1447211278,15175749.51,5931324.37,99864.38,1905029.23
|
||||
1447211529,15442994.79,5909448.56,91180.52,1953744.42
|
||||
1447211564,15175229.72,6100062.87,58254.22,1918667.68
|
||||
1447211712,15957717.02,6145969.23,77672.30,1960098.15
|
||||
1447211732,15692151.82,5725138.47,62601.55,1711560.29
|
||||
1447211755,15758474.73,6033801.22,82241.25,1995758.04
|
||||
|
|
Can't render this file because it has a wrong number of fields in line 447.
|
49
include/r3.h
49
include/r3.h
|
@ -27,40 +27,28 @@ typedef struct _edge edge;
|
|||
typedef struct _node node;
|
||||
typedef struct _route route;
|
||||
|
||||
struct _node {
|
||||
edge ** edges;
|
||||
// edge ** edge_table;
|
||||
struct _node {
|
||||
edge * edges;
|
||||
char * combined_pattern;
|
||||
pcre * pcre_pattern;
|
||||
|
||||
// #ifdef PCRE_STUDY_JIT_COMPILE
|
||||
pcre_extra * pcre_extra;
|
||||
// #endif
|
||||
|
||||
// edges are mostly less than 255
|
||||
unsigned int edge_len;
|
||||
unsigned int compare_type; // compare_type: pcre, opcode, string
|
||||
unsigned char endpoint; // endpoint, should be zero for non-endpoint nodes
|
||||
unsigned char ov_cnt; // capture vector array size for pcre
|
||||
unsigned int edge_len;
|
||||
unsigned int endpoint; // endpoint, should be zero for non-endpoint nodes
|
||||
unsigned int ov_cnt; // capture vector array size for pcre
|
||||
|
||||
|
||||
route ** routes;
|
||||
// the pointer of route data
|
||||
void * data;
|
||||
|
||||
// almost less than 255
|
||||
unsigned char edge_cap;
|
||||
unsigned char route_len;
|
||||
unsigned char route_cap;
|
||||
// <-- here comes a char[1] struct padding for alignment since we have 4 char above.
|
||||
|
||||
|
||||
/** compile-time variables here.... **/
|
||||
|
||||
/* the combined regexp pattern string from pattern_tokens */
|
||||
|
||||
route ** routes;
|
||||
|
||||
/**
|
||||
* the pointer of route data
|
||||
*/
|
||||
void * data;
|
||||
};
|
||||
} __attribute((aligned(64)));
|
||||
|
||||
#define r3_node_edge_pattern(node,i) node->edges[i]->pattern
|
||||
#define r3_node_edge_pattern_len(node,i) node->edges[i]->pattern_len
|
||||
|
@ -68,11 +56,10 @@ struct _node {
|
|||
struct _edge {
|
||||
char * pattern; // 8 bytes
|
||||
node * child; // 8 bytes
|
||||
unsigned int pattern_len; // 1 byte
|
||||
unsigned int opcode;
|
||||
// unsigned char opcode:4; // 4 bit
|
||||
unsigned char has_slug:1; // 1 bit
|
||||
};
|
||||
unsigned int pattern_len; // 4byte
|
||||
unsigned int opcode; // 4byte
|
||||
unsigned int has_slug; // 4byte
|
||||
} __attribute((aligned(64)));
|
||||
|
||||
struct _route {
|
||||
char * path;
|
||||
|
@ -87,7 +74,7 @@ struct _route {
|
|||
|
||||
char * remote_addr_pattern;
|
||||
int remote_addr_pattern_len;
|
||||
};
|
||||
} __attribute((aligned(64)));
|
||||
|
||||
typedef struct {
|
||||
str_array * vars;
|
||||
|
@ -123,7 +110,7 @@ edge * r3_node_connectl(node * n, const char * pat, int len, int strdup, node *c
|
|||
|
||||
edge * r3_node_find_edge(const node * n, const char * pat, int pat_len);
|
||||
|
||||
void r3_node_append_edge(node *n, edge *child);
|
||||
edge * r3_node_append_edge(node *n, edge *child);
|
||||
|
||||
|
||||
edge * r3_node_find_common_prefix(node *n, const char *path, int path_len, int *prefix_len, char **errstr);
|
||||
|
@ -171,6 +158,8 @@ bool r3_node_has_slug_edges(const node *n);
|
|||
|
||||
edge * r3_edge_createl(const char * pattern, int pattern_len, node * child);
|
||||
|
||||
void r3_edge_initl(edge *e, const char * pattern, int pattern_len, node * child);
|
||||
|
||||
node * r3_edge_branch(edge *e, int dl);
|
||||
|
||||
void r3_edge_free(edge * edge);
|
||||
|
|
|
@ -4,7 +4,7 @@ MAYBE_COVERAGE=--coverage
|
|||
|
||||
noinst_LTLIBRARIES = libr3core.la
|
||||
# lib_LIBRARIES = libr3.a
|
||||
libr3core_la_SOURCES = node.c edge.c str.c token.c match_entry.c slug.c
|
||||
libr3core_la_SOURCES = node.c edge.c str.c token.c match_entry.c slug.c mempool.c
|
||||
|
||||
if ENABLE_JSON
|
||||
libr3core_la_SOURCES += json.c
|
||||
|
|
21
src/edge.c
21
src/edge.c
|
@ -24,11 +24,20 @@
|
|||
#define CHECK_PTR(ptr) if (ptr == NULL) return NULL;
|
||||
|
||||
|
||||
edge * r3_edge_createl(const char * pattern, int pattern_len, node * child) {
|
||||
|
||||
void r3_edge_initl(edge *e, const char * pattern, int pattern_len, node * child)
|
||||
{
|
||||
e->pattern = (char*) pattern;
|
||||
e->pattern_len = pattern_len;
|
||||
e->opcode = 0;
|
||||
e->child = child;
|
||||
e->has_slug = r3_path_contains_slug_char(e->pattern);
|
||||
}
|
||||
|
||||
edge * r3_edge_createl(const char * pattern, int pattern_len, node * child)
|
||||
{
|
||||
edge * e = (edge*) zmalloc( sizeof(edge) );
|
||||
|
||||
CHECK_PTR(e);
|
||||
|
||||
e->pattern = (char*) pattern;
|
||||
e->pattern_len = pattern_len;
|
||||
e->opcode = 0;
|
||||
|
@ -60,9 +69,9 @@ node * r3_edge_branch(edge *e, int dl) {
|
|||
e1 = r3_edge_createl(zstrndup(s1, s1_len), s1_len, new_child);
|
||||
|
||||
// Migrate the child edges to the new edge we just created.
|
||||
for ( int i = 0 ; i < e->child->edge_len ; i++ ) {
|
||||
r3_node_append_edge(new_child, e->child->edges[i]);
|
||||
e->child->edges[i] = NULL;
|
||||
for (int i = 0 ; i < e->child->edge_len ; i++) {
|
||||
r3_node_append_edge(new_child, &e->child->edges[i]);
|
||||
// e->child->edges[i] = NULL;
|
||||
}
|
||||
e->child->edge_len = 0;
|
||||
|
||||
|
|
43
src/mempool.c
Normal file
43
src/mempool.c
Normal file
|
@ -0,0 +1,43 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "mempool.h"
|
||||
|
||||
void ex_mpool_init(ex_mpool *pmp, char *begin, size_t len)
|
||||
{
|
||||
pmp->begin = begin;
|
||||
pmp->len = len;
|
||||
pmp->index = 0;
|
||||
pmp->cflag = 0;
|
||||
}
|
||||
|
||||
void *ex_mpool_malloc(ex_mpool *pmp, size_t mlen)
|
||||
{
|
||||
void *ret = NULL;
|
||||
|
||||
size_t rIndex = pmp->index + mlen;
|
||||
if (rIndex > pmp->len) {
|
||||
ret = malloc(mlen);
|
||||
pmp->cflag = 1;
|
||||
}
|
||||
else {
|
||||
ret = pmp->begin + pmp->index;
|
||||
pmp->index = rIndex;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ex_mpool_free(ex_mpool *pmp, void *p)
|
||||
{
|
||||
/* only perform free when allocated in heap */
|
||||
if (p < (void *) pmp->begin ||
|
||||
p >= (void *) (pmp->begin + pmp->len)) {
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
|
||||
void ex_mpool_clear(ex_mpool *pmp)
|
||||
{
|
||||
pmp->index = 0;
|
||||
pmp->cflag = 0;
|
||||
}
|
||||
|
24
src/mempool.h
Normal file
24
src/mempool.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
#ifndef __ESERV_MPOOL_H__
|
||||
#define __ESERV_MPOOL_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
char *begin; /* start pos */
|
||||
size_t len; /* capacity */
|
||||
int index; /* curIndex */
|
||||
int cflag; /* clear flag */
|
||||
} ex_mpool;
|
||||
|
||||
void ex_mpool_init(ex_mpool *pmp, char *begin, size_t len);
|
||||
void *ex_mpool_malloc(ex_mpool *pmp, size_t mlen);
|
||||
void ex_mpool_free(ex_mpool *pmp, void *p);
|
||||
void ex_mpool_clear(ex_mpool *pmp);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
73
src/node.c
73
src/node.c
|
@ -13,6 +13,13 @@
|
|||
#include "slug.h"
|
||||
#include "zmalloc.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define likely(x) __builtin_expect(!!(x), 1)
|
||||
# define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
#else
|
||||
# define likely(x) !!(x)
|
||||
# define unlikely(x) !!(x)
|
||||
#endif
|
||||
|
||||
#define CHECK_PTR(ptr) if (ptr == NULL) return NULL;
|
||||
|
||||
|
@ -47,7 +54,7 @@ node * r3_tree_create(int cap) {
|
|||
node * n = (node*) zmalloc( sizeof(node) );
|
||||
CHECK_PTR(n);
|
||||
|
||||
n->edges = (edge**) zmalloc( sizeof(edge*) * cap );
|
||||
n->edges = (edge*) zmalloc(sizeof(edge) * cap);
|
||||
CHECK_PTR(n->edges);
|
||||
n->edge_len = 0;
|
||||
n->edge_cap = cap;
|
||||
|
@ -65,12 +72,9 @@ node * r3_tree_create(int cap) {
|
|||
}
|
||||
|
||||
void r3_tree_free(node * tree) {
|
||||
for (int i = 0 ; i < tree->edge_len ; i++ ) {
|
||||
if (tree->edges[i]) {
|
||||
r3_edge_free(tree->edges[ i ]);
|
||||
}
|
||||
if (tree->edges) {
|
||||
zfree(tree->edges);
|
||||
}
|
||||
zfree(tree->edges);
|
||||
zfree(tree->routes);
|
||||
if (tree->pcre_pattern) {
|
||||
pcre_free(tree->pcre_pattern);
|
||||
|
@ -104,23 +108,29 @@ edge * r3_node_connectl(node * n, const char * pat, int len, int dupl, node *chi
|
|||
}
|
||||
e = r3_edge_createl(pat, len, child);
|
||||
CHECK_PTR(e);
|
||||
r3_node_append_edge(n, e);
|
||||
return e;
|
||||
edge *e2 = r3_node_append_edge(n, e);
|
||||
zfree(e);
|
||||
return e2;
|
||||
}
|
||||
|
||||
void r3_node_append_edge(node *n, edge *e) {
|
||||
edge * r3_node_append_edge(node *n, edge *e)
|
||||
{
|
||||
if (n->edges == NULL) {
|
||||
n->edge_cap = 3;
|
||||
n->edges = zmalloc(sizeof(edge) * n->edge_cap);
|
||||
}
|
||||
if (n->edge_len >= n->edge_cap) {
|
||||
n->edge_cap *= 2;
|
||||
edge ** p = zrealloc(n->edges, sizeof(edge) * n->edge_cap);
|
||||
edge * p = zrealloc(n->edges, sizeof(edge) * n->edge_cap);
|
||||
if(p) {
|
||||
n->edges = p;
|
||||
}
|
||||
}
|
||||
n->edges[ n->edge_len++ ] = e;
|
||||
|
||||
// r3_edge_initl(
|
||||
// copy 'edge' into the edge array
|
||||
n->edges[n->edge_len] = *e;
|
||||
return &n->edges[n->edge_len++];
|
||||
}
|
||||
|
||||
|
||||
|
@ -133,11 +143,10 @@ edge * r3_node_find_edge(const node * n, const char * pat, int pat_len) {
|
|||
edge * e;
|
||||
int i;
|
||||
for (i = 0 ; i < n->edge_len ; i++ ) {
|
||||
e = n->edges[i];
|
||||
|
||||
e = &n->edges[i];
|
||||
// there is a case: "{foo}" vs "{foo:xxx}",
|
||||
// we should return the match result: full-match or partial-match
|
||||
if ( strcmp(e->pattern, pat) == 0 ) {
|
||||
if (strcmp(e->pattern, pat) == 0) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
@ -146,6 +155,7 @@ edge * r3_node_find_edge(const node * n, const char * pat, int pat_len) {
|
|||
|
||||
int r3_tree_compile(node *n, char **errstr)
|
||||
{
|
||||
int i;
|
||||
int ret = 0;
|
||||
bool use_slug = r3_node_has_slug_edges(n);
|
||||
if ( use_slug ) {
|
||||
|
@ -157,8 +167,8 @@ int r3_tree_compile(node *n, char **errstr)
|
|||
n->combined_pattern = NULL;
|
||||
}
|
||||
|
||||
for (int i = 0 ; i < n->edge_len ; i++ ) {
|
||||
if ( (ret = r3_tree_compile(n->edges[i]->child, errstr)) ) {
|
||||
for (i = 0 ; i < n->edge_len ; i++ ) {
|
||||
if ((ret = r3_tree_compile(n->edges[i].child, errstr))) {
|
||||
return ret; // stop here if error occurs
|
||||
}
|
||||
}
|
||||
|
@ -173,7 +183,7 @@ int r3_tree_compile(node *n, char **errstr)
|
|||
* Return 0 if success
|
||||
*/
|
||||
int r3_tree_compile_patterns(node * n, char **errstr) {
|
||||
edge * e = NULL;
|
||||
edge *e = NULL;
|
||||
char * p;
|
||||
char * cpat = zcalloc(sizeof(char) * 64 * 3); // XXX
|
||||
if (!cpat) {
|
||||
|
@ -185,7 +195,7 @@ int r3_tree_compile_patterns(node * n, char **errstr) {
|
|||
int opcode_cnt = 0;
|
||||
int i = 0;
|
||||
for (; i < n->edge_len ; i++) {
|
||||
e = n->edges[i];
|
||||
e = &n->edges[i];
|
||||
if (e->opcode) {
|
||||
opcode_cnt++;
|
||||
}
|
||||
|
@ -286,7 +296,7 @@ node * r3_tree_matchl(const node * n, const char * path, int path_len, match_ent
|
|||
|
||||
for (i = n->edge_len; i--; ) {
|
||||
pp = path;
|
||||
e = n->edges[i];
|
||||
e = &n->edges[i];
|
||||
switch(e->opcode) {
|
||||
case OP_EXPECT_NOSLASH:
|
||||
while (*pp != '/' && pp < pp_end) pp++;
|
||||
|
@ -305,7 +315,7 @@ node * r3_tree_matchl(const node * n, const char * path, int path_len, match_ent
|
|||
break;
|
||||
}
|
||||
// check match
|
||||
if ( (pp - path) > 0) {
|
||||
if ((pp - path) > 0) {
|
||||
if (entry) {
|
||||
str_array_append(entry->vars , zstrndup(path, pp - path));
|
||||
}
|
||||
|
@ -372,7 +382,7 @@ node * r3_tree_matchl(const node * n, const char * path, int path_len, match_ent
|
|||
continue;
|
||||
|
||||
substring_start = path + ov[2*i];
|
||||
e = n->edges[i - 1];
|
||||
e = &n->edges[i - 1];
|
||||
|
||||
if (entry && e->has_slug) {
|
||||
// append captured token to entry
|
||||
|
@ -396,7 +406,7 @@ node * r3_tree_matchl(const node * n, const char * path, int path_len, match_ent
|
|||
}
|
||||
|
||||
substring_start = path + ov[2*i];
|
||||
e = n->edges[i - 1];
|
||||
e = &n->edges[i - 1];
|
||||
|
||||
if (entry && e->has_slug) {
|
||||
// append captured token to entry
|
||||
|
@ -410,7 +420,7 @@ node * r3_tree_matchl(const node * n, const char * path, int path_len, match_ent
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if ( (e = r3_node_find_edge_str(n, path, path_len)) != NULL ) {
|
||||
if ((e = r3_node_find_edge_str(n, path, path_len)) != NULL) {
|
||||
restlen = path_len - e->pattern_len;
|
||||
if (restlen == 0) {
|
||||
return e->child && e->child->endpoint > 0 ? e->child : NULL;
|
||||
|
@ -437,13 +447,14 @@ route * r3_tree_match_route(const node *tree, match_entry * entry) {
|
|||
}
|
||||
|
||||
inline edge * r3_node_find_edge_str(const node * n, const char * str, int str_len) {
|
||||
char firstbyte = *str;
|
||||
edge * e;
|
||||
unsigned int i;
|
||||
char firstbyte = *str;
|
||||
for (i = n->edge_len; i--; ) {
|
||||
edge *e = n->edges[i];
|
||||
e = &n->edges[i];
|
||||
if (firstbyte == e->pattern[0]) {
|
||||
if (strncmp(e->pattern, str, e->pattern_len) == 0 ) {
|
||||
return n->edges[i];
|
||||
if (strncmp(e->pattern, str, e->pattern_len) == 0) {
|
||||
return &n->edges[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -531,11 +542,11 @@ edge * r3_node_find_common_prefix(node *n, const char *path, int path_len, int *
|
|||
edge *e = NULL;
|
||||
for(i = 0 ; i < n->edge_len ; i++ ) {
|
||||
// ignore all edges with slug
|
||||
prefix = strndiff( (char*) path, n->edges[i]->pattern, n->edges[i]->pattern_len);
|
||||
prefix = strndiff( (char*) path, n->edges[i].pattern, n->edges[i].pattern_len);
|
||||
|
||||
// no common, consider insert a new edge
|
||||
if ( prefix > 0 ) {
|
||||
e = n->edges[i];
|
||||
e = &n->edges[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -753,7 +764,7 @@ bool r3_node_has_slug_edges(const node *n) {
|
|||
bool found = FALSE;
|
||||
edge *e;
|
||||
for ( int i = 0 ; i < n->edge_len ; i++ ) {
|
||||
e = n->edges[i];
|
||||
e = &n->edges[i];
|
||||
e->has_slug = r3_path_contains_slug_char(e->pattern);
|
||||
if (e->has_slug)
|
||||
found = TRUE;
|
||||
|
@ -780,7 +791,7 @@ void r3_tree_dump(const node * n, int level) {
|
|||
printf("\n");
|
||||
|
||||
for ( int i = 0 ; i < n->edge_len ; i++ ) {
|
||||
edge * e = n->edges[i];
|
||||
edge * e = &n->edges[i];
|
||||
print_indent(level + 1);
|
||||
printf("|-\"%s\"", e->pattern);
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
# set(TEST_LIBS ${TEST_LIBS} ${CHECK_LIBRARIES} judy libr3)
|
||||
# set(TEST_LIBS ${TEST_LIBS} ${CHECK_LIBRARIES} judy libr3)
|
||||
include_directories("${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}")
|
||||
find_package(Check REQUIRED)
|
||||
find_package(PCRE REQUIRED)
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
unsigned long unixtime() {
|
||||
struct timeval tp;
|
||||
if (gettimeofday((struct timeval *) &tp, (NUL)) == 0) {
|
||||
if (gettimeofday((struct timeval *) &tp, (NULL)) == 0) {
|
||||
return tp.tv_sec;
|
||||
}
|
||||
return 0;
|
||||
|
@ -30,7 +30,7 @@ double microtime() {
|
|||
struct timeval tp;
|
||||
long sec = 0L;
|
||||
double msec = 0.0;
|
||||
if (gettimeofday((struct timeval *) &tp, (NUL)) == 0) {
|
||||
if (gettimeofday((struct timeval *) &tp, (NULL)) == 0) {
|
||||
msec = (double) (tp.tv_usec / MICRO_IN_SEC);
|
||||
sec = tp.tv_sec;
|
||||
if (msec >= 1.0)
|
||||
|
|
Loading…
Reference in a new issue