lwes 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/ChangeLog CHANGED
@@ -1,3 +1,8 @@
1
+ Version 0.4.0 (erik-s-chang)
2
+ * large performance improvements for ESF + Struct users with large events,
3
+ one real world app is nearly twice as fast
4
+ * GC safety fixes when raising exceptions
5
+
1
6
  Version 0.3.1 (erik-s-chang)
2
7
  * fix tests and enable Ruby warnings for tests
3
8
 
data/ext/lwes/emitter.c CHANGED
@@ -1,14 +1,70 @@
1
1
  #include "lwes_ruby.h"
2
2
 
3
- static VALUE cLWES_Emitter;
4
- static ID id_TYPE_DB, id_TYPE_LIST, id_NAME;
5
- static ID id_new;
3
+ static VALUE ENC; /* LWES_ENCODING */
4
+ static ID id_TYPE_DB, id_TYPE_LIST, id_NAME, id_HAVE_ENCODING;
5
+ static ID id_new, id_enc, id_size;
6
+ static ID sym_enc;
7
+
8
+ static void dump_name(VALUE name, LWES_BYTE_P buf, size_t *off)
9
+ {
10
+ char *s = RSTRING_PTR(name);
11
+
12
+ if (marshall_SHORT_STRING(s, buf, MAX_MSG_SIZE, off) > 0)
13
+ return;
14
+ rb_raise(rb_eRuntimeError, "failed to dump name=%s", s);
15
+ }
16
+
17
+ static int dump_bool(VALUE name, VALUE val, LWES_BYTE_P buf, size_t *off)
18
+ {
19
+ LWES_BOOLEAN tmp = FALSE;
20
+
21
+ if (val == Qtrue) {
22
+ tmp = TRUE;
23
+ } else if (val != Qfalse) {
24
+ volatile VALUE raise_inspect;
25
+
26
+ rb_raise(rb_eTypeError, "non-boolean set for %s: %s",
27
+ RSTRING_PTR(name),
28
+ RAISE_INSPECT(val));
29
+ }
30
+ dump_name(name, buf, off);
31
+ lwesrb_dump_type(LWES_BOOLEAN_TOKEN, buf, off);
32
+ return marshall_BOOLEAN(tmp, buf, MAX_MSG_SIZE, off);
33
+ }
34
+
35
+ static int dump_string(VALUE name, VALUE val, LWES_BYTE_P buf, size_t *off)
36
+ {
37
+ volatile VALUE raise_inspect;
38
+
39
+ if (TYPE(val) != T_STRING)
40
+ rb_raise(rb_eTypeError, "not a string: %s",
41
+ RAISE_INSPECT(val));
42
+ dump_name(name, buf, off);
43
+ lwesrb_dump_type(LWES_STRING_TOKEN, buf, off);
44
+ return marshall_LONG_STRING(RSTRING_PTR(val), buf, MAX_MSG_SIZE, off);
45
+ }
46
+
47
+ static void dump_enc(VALUE enc, LWES_BYTE_P buf, size_t *off)
48
+ {
49
+ dump_name(ENC, buf, off);
50
+ lwesrb_dump_num(LWES_INT_16_TOKEN, enc, buf, off);
51
+ }
52
+
53
+ static char *my_strdup(const char *str)
54
+ {
55
+ long len = strlen(str) + 1;
56
+ char *rv = xmalloc(len);
57
+
58
+ memcpy(rv, str, len);
59
+
60
+ return rv;
61
+ }
6
62
 
7
63
  /* the underlying struct for LWES::Emitter */
8
64
  struct _rb_lwes_emitter {
9
65
  struct lwes_emitter *emitter;
10
- LWES_CONST_SHORT_STRING address;
11
- LWES_CONST_SHORT_STRING iface;
66
+ char *address;
67
+ char *iface;
12
68
  LWES_U_INT_32 port;
13
69
  LWES_BOOLEAN emit_heartbeat;
14
70
  LWES_INT_16 freq;
@@ -32,28 +88,11 @@ static void rle_free(void *ptr)
32
88
 
33
89
  if (rle->emitter)
34
90
  lwes_emitter_destroy(rle->emitter);
91
+ xfree(rle->address);
92
+ xfree(rle->iface);
35
93
  xfree(ptr);
36
94
  }
37
95
 
38
- static struct lwes_event *
39
- lwesrb_event_create(struct lwes_event_type_db *db, VALUE name)
40
- {
41
- int gc_retry = 1;
42
- const char *event_name = RSTRING_PTR(name);
43
- struct lwes_event *event;
44
-
45
- retry:
46
- event = lwes_event_create(db, event_name);
47
- if (!event) {
48
- if (--gc_retry == 0) {
49
- rb_gc();
50
- goto retry;
51
- }
52
- rb_raise(rb_eRuntimeError, "failed to create lwes_event");
53
- }
54
- return event;
55
- }
56
-
57
96
  /* called by the GC when object is allocated */
58
97
  static VALUE rle_alloc(VALUE klass)
59
98
  {
@@ -73,202 +112,213 @@ static VALUE rle_alloc(VALUE klass)
73
112
  */
74
113
  static VALUE event_hash_iter_i(VALUE kv, VALUE memo)
75
114
  {
76
- VALUE *tmp;
115
+ volatile VALUE raise_inspect;
116
+ VALUE *tmp = (VALUE *)memo;
77
117
  VALUE val;
78
- struct lwes_event *event = (struct lwes_event *)memo;
79
- LWES_CONST_SHORT_STRING name;
118
+ VALUE name;
80
119
  int rv = 0;
81
- int gc_retry = 1;
120
+ LWES_BYTE_P buf = (LWES_BYTE_P)tmp[0];
121
+ size_t *off = (size_t *)tmp[1];
82
122
 
83
- assert(TYPE(kv) == T_ARRAY &&
84
- "hash iteration not giving key-value pairs");
123
+ if (TYPE(kv) != T_ARRAY || RARRAY_LEN(kv) != 2)
124
+ rb_raise(rb_eTypeError,
125
+ "hash iteration not giving key-value pairs");
85
126
  tmp = RARRAY_PTR(kv);
86
- name = RSTRING_PTR(rb_obj_as_string(tmp[0]));
127
+ name = tmp[0];
128
+
129
+ if (name == sym_enc) return Qnil; /* already dumped first */
130
+
131
+ name = rb_obj_as_string(name);
132
+
133
+ if (strcmp(RSTRING_PTR(name), LWES_ENCODING) == 0)
134
+ return Qnil;
135
+
87
136
  val = tmp[1];
88
137
 
89
- retry:
90
138
  switch (TYPE(val)) {
91
139
  case T_TRUE:
92
- rv = lwes_event_set_BOOLEAN(event, name, TRUE);
93
- break;
94
140
  case T_FALSE:
95
- rv = lwes_event_set_BOOLEAN(event, name, FALSE);
141
+ rv = dump_bool(name, val, buf, off);
96
142
  break;
97
143
  case T_ARRAY:
98
- rv = lwesrb_event_set_numeric(event, name, val);
99
- break;
144
+ dump_name(name, buf, off);
145
+ lwesrb_dump_num_ary(val, buf, off);
146
+ return Qnil;
100
147
  case T_STRING:
101
- rv = lwes_event_set_STRING(event, name, RSTRING_PTR(val));
148
+ rv = dump_string(name, val, buf, off);
102
149
  break;
103
150
  }
104
- if (rv > 0) {
151
+
152
+ if (rv > 0)
105
153
  return Qnil;
106
- } else if (rv == 0) {
107
- rb_raise(rb_eArgError, "unhandled type %s=%s for event=%s",
108
- name, RSTRING_PTR(rb_inspect(val)), event->eventName);
109
- } else {
110
- /* looking at the lwes source code, -3 is allocation errors */
111
- if (rv == -3 && --gc_retry == 0) {
112
- rb_gc();
113
- goto retry;
114
- }
115
- rb_raise(rb_eRuntimeError, "failed to set %s=%s for event=%s",
116
- name, RSTRING_PTR(rb_inspect(val)), event->eventName);
117
- }
154
+
155
+ rb_raise(rb_eArgError, "unhandled type %s=%s",
156
+ RSTRING_PTR(name), RAISE_INSPECT(val));
118
157
  return Qfalse;
119
158
  }
120
159
 
121
- static VALUE _emit_hash(VALUE _tmp)
160
+ static VALUE emit_hash(VALUE self, VALUE name, VALUE event)
122
161
  {
123
- VALUE *tmp = (VALUE *)_tmp;
124
- VALUE self = tmp[0];
125
- VALUE _event = tmp[1];
126
- struct lwes_event *event = (struct lwes_event *)tmp[2];
162
+ struct _rb_lwes_emitter *rle = _rle(self);
163
+ LWES_BYTE_P buf = rle->emitter->buffer;
164
+ VALUE tmp[2];
165
+ size_t off = 0;
166
+ VALUE enc;
167
+ int size = NUM2INT(rb_funcall(event, id_size, 0, 0));
168
+ int rv;
169
+
170
+ tmp[0] = (VALUE)buf;
171
+ tmp[1] = (VALUE)&off;
172
+
173
+ if (size < 0 || size > UINT16_MAX)
174
+ rb_raise(rb_eRangeError, "hash size out of uint16 range");
175
+
176
+ /* event name first */
177
+ dump_name(name, buf, &off);
178
+
179
+ /* number of attributes second */
180
+ rv = marshall_U_INT_16((LWES_U_INT_16)size, buf, MAX_MSG_SIZE, &off);
181
+ if (rv <= 0)
182
+ rb_raise(rb_eRuntimeError, "failed to dump num_attrs");
183
+
184
+ /* dump encoding before other fields */
185
+ enc = rb_hash_aref(event, sym_enc);
186
+ if (NIL_P(enc))
187
+ enc = rb_hash_aref(event, ENC);
188
+ if (! NIL_P(enc))
189
+ dump_enc(enc, buf, &off);
127
190
 
128
- rb_iterate(rb_each, _event, event_hash_iter_i, (VALUE)event);
129
- if (lwes_emitter_emit(_rle(self)->emitter, event) < 0)
191
+ /* the rest of the fields */
192
+ rb_iterate(rb_each, event, event_hash_iter_i, (VALUE)&tmp);
193
+
194
+ if (lwes_emitter_emit_bytes(rle->emitter, buf, off) < 0)
130
195
  rb_raise(rb_eRuntimeError, "failed to emit event");
131
196
 
132
- return _event;
197
+ return event;
133
198
  }
134
199
 
135
200
  static void
136
- set_field(
137
- struct lwes_event *event,
138
- LWES_CONST_SHORT_STRING name,
201
+ marshal_field(
202
+ VALUE name,
139
203
  LWES_TYPE type,
140
- VALUE val)
204
+ VALUE val,
205
+ LWES_BYTE_P buf,
206
+ size_t *off)
141
207
  {
142
- int gc_retry = 1;
143
- int rv;
208
+ volatile VALUE raise_inspect;
144
209
 
145
- retry:
146
210
  switch (type) {
147
- case LWES_TYPE_BOOLEAN:
148
- if (val == Qfalse)
149
- rv = lwes_event_set_BOOLEAN(event, name, FALSE);
150
- else if (val == Qtrue)
151
- rv = lwes_event_set_BOOLEAN(event, name, TRUE);
152
- else
153
- rb_raise(rb_eTypeError, "non-boolean set for %s: %s",
154
- name, RSTRING_PTR(rb_inspect(val)));
155
- break;
156
211
  case LWES_TYPE_STRING:
157
- if (TYPE(val) != T_STRING)
158
- rb_raise(rb_eTypeError, "non-String set for %s: %s",
159
- name, RSTRING_PTR(rb_inspect(val)));
160
- rv = lwes_event_set_STRING(event, name, RSTRING_PTR(val));
212
+ if (dump_string(name, val, buf, off) > 0)
213
+ return;
214
+ break;
215
+ case LWES_TYPE_BOOLEAN:
216
+ if (dump_bool(name, val, buf, off) > 0)
217
+ return;
161
218
  break;
162
219
  default:
163
- rv = lwesrb_event_set_num(event, name, type, val);
164
- }
165
- if (rv > 0) {
220
+ dump_name(name, buf, off);
221
+ lwesrb_dump_num(type, val, buf, off);
166
222
  return;
167
- } else {
168
- if (rv == -3 && --gc_retry == 0) {
169
- rb_gc();
170
- goto retry;
171
- }
172
- rb_raise(rb_eRuntimeError,
173
- "failed to set %s=%s for event=%s (error: %d)",
174
- name, RSTRING_PTR(rb_inspect(val)),
175
- event->eventName, rv);
176
223
  }
177
224
 
178
- assert(0 && "you should never get here (set_field)");
225
+ rb_raise(rb_eRuntimeError, "failed to set %s=%s",
226
+ RSTRING_PTR(name), RAISE_INSPECT(val));
179
227
  }
180
228
 
181
- static VALUE _emit_struct(VALUE _argv)
229
+ static void lwes_struct_class(
230
+ VALUE *event_class,
231
+ VALUE *name,
232
+ VALUE *type_list,
233
+ VALUE *have_enc,
234
+ VALUE event)
182
235
  {
183
- VALUE *argv = (VALUE *)_argv;
184
- VALUE self = argv[0];
185
- VALUE _event = argv[1];
186
- struct lwes_event *event = (struct lwes_event *)argv[2];
187
- VALUE type_list = argv[3];
188
- long i;
189
- VALUE *tmp;
190
-
191
- if (TYPE(type_list) != T_ARRAY)
192
- rb_raise(rb_eArgError, "could not get TYPE_LIST const");
236
+ VALUE type_db;
237
+ volatile VALUE raise_inspect;
193
238
 
194
- i = RARRAY_LEN(type_list);
195
- for (tmp = RARRAY_PTR(type_list); --i >= 0; tmp++) {
196
- /* inner: [ :field_sym, "field_name", type ] */
197
- VALUE *inner = RARRAY_PTR(*tmp);
198
- VALUE val = rb_struct_aref(_event, inner[0]);
199
- LWES_CONST_SHORT_STRING name;
200
- LWES_TYPE type;
239
+ *event_class = CLASS_OF(event);
240
+ type_db = rb_const_get(*event_class, id_TYPE_DB);
201
241
 
202
- if (NIL_P(val))
203
- continue;
242
+ if (CLASS_OF(type_db) != cLWES_TypeDB)
243
+ rb_raise(rb_eArgError, "class does not have valid TYPE_DB");
204
244
 
205
- name = RSTRING_PTR(inner[1]);
206
- type = NUM2INT(inner[2]);
207
- set_field(event, name, type, val);
208
- }
245
+ *name = rb_const_get(*event_class, id_NAME);
246
+ if (TYPE(*name) != T_STRING)
247
+ rb_raise(rb_eArgError,
248
+ "could not get valid const NAME: %s",
249
+ RAISE_INSPECT(event));
209
250
 
210
- if (lwes_emitter_emit(_rle(self)->emitter, event) < 0)
211
- rb_raise(rb_eRuntimeError, "failed to emit event");
251
+ *type_list = rb_const_get(*event_class, id_TYPE_LIST);
252
+ if (TYPE(*type_list) != T_ARRAY)
253
+ rb_raise(rb_eArgError,
254
+ "could not get valid const TYPE_LIST: %s",
255
+ RAISE_INSPECT(event));
212
256
 
213
- return _event;
257
+ *have_enc = rb_const_get(*event_class, id_HAVE_ENCODING);
214
258
  }
215
259
 
216
- static VALUE _destroy_event(VALUE _event)
260
+ static VALUE emit_struct(VALUE self, VALUE event)
217
261
  {
218
- struct lwes_event *event = (struct lwes_event *)_event;
219
-
220
- assert(event && "destroying NULL event");
221
- lwes_event_destroy(event);
222
-
223
- return Qnil;
224
- }
262
+ VALUE event_class, name, type_list, have_enc;
263
+ struct _rb_lwes_emitter *rle = _rle(self);
264
+ LWES_BYTE_P buf = rle->emitter->buffer;
265
+ size_t off = 0;
266
+ long i;
267
+ VALUE *tmp;
268
+ LWES_U_INT_16 num_attr = 0;
269
+ size_t num_attr_off;
270
+ VALUE *flds;
225
271
 
226
- static VALUE emit_hash(VALUE self, VALUE name, VALUE _event)
227
- {
228
- VALUE tmp[3];
229
- struct lwes_event *event = lwesrb_event_create(NULL, name);
272
+ lwes_struct_class(&event_class, &name, &type_list, &have_enc, event);
230
273
 
231
- tmp[0] = self;
232
- tmp[1] = _event;
233
- tmp[2] = (VALUE)event;
234
- rb_ensure(_emit_hash, (VALUE)&tmp, _destroy_event, (VALUE)event);
274
+ /* event name */
275
+ dump_name(name, buf, &off);
235
276
 
236
- return _event;
237
- }
277
+ /* number of attributes, use a placeholder until we've iterated */
278
+ num_attr_off = off;
279
+ if (marshall_U_INT_16(0, buf, MAX_MSG_SIZE, &off) < 0)
280
+ rb_raise(rb_eRuntimeError,
281
+ "failed to marshal number_of_attributes");
282
+
283
+ /* dump encoding before other fields */
284
+ if (have_enc == Qtrue) {
285
+ VALUE enc = rb_funcall(event, id_enc, 0, 0);
286
+ if (! NIL_P(enc)) {
287
+ ++num_attr;
288
+ dump_enc(enc, buf, &off);
289
+ }
290
+ }
238
291
 
239
- static struct lwes_event_type_db * get_type_db(VALUE event_class)
240
- {
241
- VALUE type_db = rb_const_get(event_class, id_TYPE_DB);
292
+ i = RARRAY_LEN(type_list);
293
+ flds = RSTRUCT_PTR(event);
294
+ tmp = RARRAY_PTR(type_list);
295
+ for (; --i >= 0; tmp++, flds++) {
296
+ /* inner: [ :field_sym, "field_name", type ] */
297
+ VALUE *inner = RARRAY_PTR(*tmp);
298
+ VALUE val, name;
299
+ LWES_TYPE type;
242
300
 
243
- if (CLASS_OF(type_db) != cLWES_TypeDB)
244
- rb_raise(rb_eArgError, "class does not have valid TYPE_DB");
301
+ if (inner[0] == sym_enc) /* encoding was already dumped */
302
+ continue;
245
303
 
246
- return lwesrb_get_type_db(type_db);
247
- }
304
+ val = *flds;
305
+ if (NIL_P(val))
306
+ continue; /* LWES doesn't know nil */
248
307
 
249
- static VALUE emit_struct(VALUE self, VALUE _event)
250
- {
251
- VALUE argv[4];
252
- VALUE event_class = CLASS_OF(_event);
253
- struct lwes_event_type_db *db = get_type_db(event_class);
254
- struct lwes_event *event;
255
- VALUE name = rb_const_get(event_class, id_NAME);
256
- VALUE type_list = rb_const_get(event_class, id_TYPE_LIST);
257
-
258
- if (TYPE(name) != T_STRING || TYPE(type_list) != T_ARRAY)
259
- rb_raise(rb_eArgError,
260
- "could not get class NAME or TYPE_LIST from: %s",
261
- RSTRING_PTR(rb_inspect(_event)));
308
+ name = inner[1];
309
+ type = NUM2INT(inner[2]);
310
+ ++num_attr;
311
+ marshal_field(name, type, val, buf, &off);
312
+ }
262
313
 
263
- event = lwesrb_event_create(db, name);
314
+ /* now we've iterated, we can accurately give num_attr */
315
+ if (marshall_U_INT_16(num_attr, buf, MAX_MSG_SIZE, &num_attr_off) <= 0)
316
+ rb_raise(rb_eRuntimeError, "failed to marshal num_attr");
264
317
 
265
- argv[0] = self;
266
- argv[1] = _event;
267
- argv[2] = (VALUE)event;
268
- argv[3] = type_list;
269
- rb_ensure(_emit_struct, (VALUE)&argv, _destroy_event, (VALUE)event);
318
+ if (lwes_emitter_emit_bytes(rle->emitter, buf, off) < 0)
319
+ rb_raise(rb_eRuntimeError, "failed to emit event");
270
320
 
271
- return _event;
321
+ return event;
272
322
  }
273
323
 
274
324
  /*
@@ -280,12 +330,12 @@ static VALUE emit_struct(VALUE self, VALUE _event)
280
330
  */
281
331
  static VALUE emitter_ltlt(VALUE self, VALUE event)
282
332
  {
283
- if (TYPE(event) != T_STRUCT)
284
- rb_raise(rb_eArgError,
285
- "Must be a Struct: %s",
286
- RSTRING_PTR(rb_inspect(event)));
333
+ volatile VALUE raise_inspect;
334
+
335
+ if (TYPE(event) == T_STRUCT)
336
+ return emit_struct(self, event);
287
337
 
288
- return emit_struct(self, event);
338
+ rb_raise(rb_eArgError, "Must be a Struct: %s", RAISE_INSPECT(event));
289
339
  }
290
340
 
291
341
  /*
@@ -302,6 +352,7 @@ static VALUE emitter_ltlt(VALUE self, VALUE event)
302
352
  */
303
353
  static VALUE emitter_emit(int argc, VALUE *argv, VALUE self)
304
354
  {
355
+ volatile VALUE raise_inspect;
305
356
  VALUE name = Qnil;
306
357
  VALUE event = Qnil;
307
358
  argc = rb_scan_args(argc, argv, "11", &name, &event);
@@ -335,7 +386,7 @@ static VALUE emitter_emit(int argc, VALUE *argv, VALUE self)
335
386
  default:
336
387
  rb_raise(rb_eArgError,
337
388
  "bad argument: %s, must be a String, Struct or Class",
338
- RSTRING_PTR(rb_inspect(name)));
389
+ RAISE_INSPECT(name));
339
390
  }
340
391
 
341
392
  assert(0 && "should never get here");
@@ -388,6 +439,9 @@ static VALUE init_copy(VALUE dest, VALUE obj)
388
439
  struct _rb_lwes_emitter *src = _rle(obj);
389
440
 
390
441
  memcpy(dst, src, sizeof(*dst));
442
+ dst->address = my_strdup(src->address);
443
+ if (dst->iface)
444
+ dst->iface = my_strdup(src->iface);
391
445
  lwesrb_emitter_create(dst);
392
446
 
393
447
  assert(dst->emitter && dst->emitter != src->emitter &&
@@ -414,7 +468,7 @@ static VALUE _create(VALUE self, VALUE options)
414
468
  address = rb_hash_aref(options, ID2SYM(rb_intern("address")));
415
469
  if (TYPE(address) != T_STRING)
416
470
  rb_raise(rb_eTypeError, ":address must be a string");
417
- rle->address = RSTRING_PTR(address);
471
+ rle->address = my_strdup(RSTRING_PTR(address));
418
472
 
419
473
  iface = rb_hash_aref(options, ID2SYM(rb_intern("iface")));
420
474
  switch (TYPE(iface)) {
@@ -422,7 +476,7 @@ static VALUE _create(VALUE self, VALUE options)
422
476
  rle->iface = NULL;
423
477
  break;
424
478
  case T_STRING:
425
- rle->iface = RSTRING_PTR(iface);
479
+ rle->iface = my_strdup(RSTRING_PTR(iface));
426
480
  break;
427
481
  default:
428
482
  rb_raise(rb_eTypeError, ":iface must be a String or nil");
@@ -463,7 +517,8 @@ static VALUE _create(VALUE self, VALUE options)
463
517
  void lwesrb_init_emitter(void)
464
518
  {
465
519
  VALUE mLWES = rb_define_module("LWES");
466
- cLWES_Emitter = rb_define_class_under(mLWES, "Emitter", rb_cObject);
520
+ VALUE cLWES_Emitter =
521
+ rb_define_class_under(mLWES, "Emitter", rb_cObject);
467
522
 
468
523
  rb_define_method(cLWES_Emitter, "<<", emitter_ltlt, 1);
469
524
  rb_define_method(cLWES_Emitter, "emit", emitter_emit, -1);
@@ -474,5 +529,12 @@ void lwesrb_init_emitter(void)
474
529
  LWESRB_MKID(TYPE_DB);
475
530
  LWESRB_MKID(TYPE_LIST);
476
531
  LWESRB_MKID(NAME);
477
- LWESRB_MKID(new);
532
+ LWESRB_MKID(HAVE_ENCODING);
533
+ LWESRB_MKID(new);
534
+ LWESRB_MKID(size);
535
+ id_enc = rb_intern(LWES_ENCODING);
536
+ sym_enc = ID2SYM(id_enc);
537
+
538
+ ENC = rb_obj_freeze(rb_str_new2(LWES_ENCODING));
539
+ rb_define_const(mLWES, "ENCODING", ENC);
478
540
  }
data/ext/lwes/lwes.c CHANGED
@@ -1,11 +1,9 @@
1
1
  #include "lwes_ruby.h"
2
2
 
3
- static VALUE mLWES;
4
-
5
3
  /* initialize the extension, Ruby automatically picks this up */
6
4
  void Init_lwes_ext(void)
7
5
  {
8
- mLWES = rb_define_module("LWES");
6
+ VALUE mLWES = rb_define_module("LWES");
9
7
 
10
8
  #define LWES_TYPE_CONST(name) \
11
9
  rb_define_const(mLWES, #name, INT2FIX(LWES_TYPE_##name))
data/ext/lwes/lwes_ruby.h CHANGED
@@ -19,16 +19,11 @@ void lwesrb_init_emitter(void);
19
19
 
20
20
  void lwesrb_init_numeric(void);
21
21
 
22
- int lwesrb_event_set_numeric(
23
- struct lwes_event *event,
24
- LWES_CONST_SHORT_STRING name,
25
- VALUE array);
22
+ void lwesrb_dump_type(LWES_BYTE type, LWES_BYTE_P buf, size_t *off);
26
23
 
27
- int lwesrb_event_set_num(
28
- struct lwes_event *event,
29
- LWES_CONST_SHORT_STRING name,
30
- LWES_TYPE type,
31
- VALUE val);
24
+ void lwesrb_dump_num(LWES_BYTE type, VALUE val, LWES_BYTE_P buf, size_t *off);
25
+
26
+ void lwesrb_dump_num_ary(VALUE array, LWES_BYTE_P buf, size_t *off);
32
27
 
33
28
  #ifndef RSTRING_PTR
34
29
  # define RSTRING_PTR(s) (RSTRING(s)->ptr)
@@ -40,4 +35,11 @@ int lwesrb_event_set_num(
40
35
  # define RARRAY_LEN(s) (RARRAY(s)->len)
41
36
  #endif
42
37
 
38
+ #ifndef RSTRUCT_PTR
39
+ # define RSTRUCT_PTR(s) (RSTRUCT(s)->ptr)
40
+ # define RSTRUCT_LEN(s) (RSTRUCT(s)->len)
41
+ #endif
42
+
43
+ #define RAISE_INSPECT(v) RSTRING_PTR(raise_inspect = rb_inspect(v))
44
+
43
45
  #endif /* LWES_RUBY_H */
data/ext/lwes/numeric.c CHANGED
@@ -7,8 +7,14 @@ static ID
7
7
  sym_int64, sym_uint64,
8
8
  sym_ip_addr;
9
9
 
10
- static int set_uint16(
11
- struct lwes_event *event, LWES_CONST_SHORT_STRING name, VALUE val)
10
+ void lwesrb_dump_type(LWES_BYTE type, LWES_BYTE_P buf, size_t *off)
11
+ {
12
+ if (marshall_BYTE(type, buf, MAX_MSG_SIZE, off) > 0)
13
+ return;
14
+ rb_raise(rb_eRuntimeError, "failed to dump type=%02x", (unsigned)type);
15
+ }
16
+
17
+ static int dump_uint16(VALUE val, LWES_BYTE_P buf, size_t *off)
12
18
  {
13
19
  int32_t tmp = NUM2INT(val);
14
20
 
@@ -17,24 +23,24 @@ static int set_uint16(
17
23
  if (tmp > UINT16_MAX)
18
24
  rb_raise(rb_eRangeError, ":uint16 too large: %d", tmp);
19
25
 
20
- return lwes_event_set_U_INT_16(event, name, (LWES_U_INT_16)tmp);
26
+ lwesrb_dump_type(LWES_U_INT_16_TOKEN, buf, off);
27
+ return marshall_U_INT_16((LWES_U_INT_16)tmp, buf, MAX_MSG_SIZE, off);
21
28
  }
22
29
 
23
- static int set_int16(
24
- struct lwes_event *event, LWES_CONST_SHORT_STRING name, VALUE val)
30
+ static int dump_int16(VALUE val, LWES_BYTE_P buf, size_t *off)
25
31
  {
26
- int tmp = NUM2INT(val);
32
+ int32_t tmp = NUM2INT(val);
27
33
 
28
34
  if (tmp > INT16_MAX)
29
35
  rb_raise(rb_eRangeError, ":int16 too large: %i", tmp);
30
36
  if (tmp < INT16_MIN)
31
37
  rb_raise(rb_eRangeError, ":int16 too small: %i", tmp);
32
38
 
33
- return lwes_event_set_INT_16(event, name, (LWES_INT_16)tmp);
39
+ lwesrb_dump_type(LWES_INT_16_TOKEN, buf, off);
40
+ return marshall_INT_16((LWES_INT_16)tmp, buf, MAX_MSG_SIZE, off);
34
41
  }
35
42
 
36
- static int set_uint32(
37
- struct lwes_event *event, LWES_CONST_SHORT_STRING name, VALUE val)
43
+ static int dump_uint32(VALUE val, LWES_BYTE_P buf, size_t *off)
38
44
  {
39
45
  LONG_LONG tmp = NUM2LL(val);
40
46
 
@@ -43,11 +49,11 @@ static int set_uint32(
43
49
  if (tmp > UINT32_MAX)
44
50
  rb_raise(rb_eRangeError, ":uint32 too large: %lli", tmp);
45
51
 
46
- return lwes_event_set_U_INT_32(event, name, (LWES_U_INT_32)tmp);
52
+ lwesrb_dump_type(LWES_U_INT_32_TOKEN, buf, off);
53
+ return marshall_U_INT_32((LWES_U_INT_32)tmp, buf, MAX_MSG_SIZE, off);
47
54
  }
48
55
 
49
- static int set_int32(
50
- struct lwes_event *event, LWES_CONST_SHORT_STRING name, VALUE val)
56
+ static int dump_int32(VALUE val, LWES_BYTE_P buf, size_t *off)
51
57
  {
52
58
  LONG_LONG tmp = NUM2LL(val);
53
59
 
@@ -56,66 +62,63 @@ static int set_int32(
56
62
  if (tmp < INT32_MIN)
57
63
  rb_raise(rb_eRangeError, ":int32 too small: %lli", tmp);
58
64
 
59
- return lwes_event_set_INT_32(event, name, (LWES_INT_32)tmp);
65
+ lwesrb_dump_type(LWES_INT_32_TOKEN, buf, off);
66
+ return marshall_INT_32((LWES_INT_32)tmp, buf, MAX_MSG_SIZE, off);
60
67
  }
61
68
 
62
- static int set_uint64(
63
- struct lwes_event *event, LWES_CONST_SHORT_STRING name, VALUE val)
69
+ static int dump_uint64(VALUE val, LWES_BYTE_P buf, size_t *off)
64
70
  {
65
71
  unsigned LONG_LONG tmp = NUM2ULL(val); /* can raise RangeError */
66
72
  ID type = TYPE(val);
67
73
 
68
74
  if ((type == T_FIXNUM && FIX2LONG(val) < 0) ||
69
- (type == T_BIGNUM && RTEST(rb_funcall(val, '<', 1, INT2FIX(0)))))
75
+ (type == T_BIGNUM && RTEST(rb_funcall(val, '<', 1, INT2FIX(0))))) {
76
+ volatile VALUE raise_inspect;
77
+
70
78
  rb_raise(rb_eRangeError, ":uint64 negative: %s",
71
- RSTRING_PTR(rb_inspect(val)));
79
+ RAISE_INSPECT(val));
80
+ }
72
81
 
73
- return lwes_event_set_U_INT_64(event, name, (LWES_U_INT_64)tmp);
82
+ lwesrb_dump_type(LWES_U_INT_64_TOKEN, buf, off);
83
+ return marshall_U_INT_64((LWES_U_INT_64)tmp, buf, MAX_MSG_SIZE, off);
74
84
  }
75
85
 
76
- static int set_int64(
77
- struct lwes_event *event, LWES_CONST_SHORT_STRING name, VALUE val)
86
+ static int dump_int64(VALUE val, LWES_BYTE_P buf, size_t *off)
78
87
  {
79
88
  LONG_LONG tmp = NUM2LL(val); /* can raise RangeError */
80
89
 
81
- return lwes_event_set_INT_64(event, name, (LWES_INT_64)tmp);
90
+ lwesrb_dump_type(LWES_INT_64_TOKEN, buf, off);
91
+ return marshall_INT_64((LWES_INT_64)tmp, buf, MAX_MSG_SIZE, off);
82
92
  }
83
93
 
84
- static int set_ip_addr(
85
- struct lwes_event *event, LWES_CONST_SHORT_STRING name, VALUE val)
94
+ static int dump_ip_addr(VALUE val, LWES_BYTE_P buf, size_t *off)
86
95
  {
96
+ LWES_IP_ADDR addr;
97
+ volatile VALUE raise_inspect;
98
+
87
99
  switch (TYPE(val)) {
88
100
  case T_STRING:
89
- {
90
- LWES_CONST_SHORT_STRING addr = RSTRING_PTR(val);
91
- return lwes_event_set_IP_ADDR_w_string(event, name, addr);
92
- }
101
+ addr.s_addr = inet_addr(RSTRING_PTR(val));
102
+ break;
93
103
  case T_FIXNUM:
94
104
  case T_BIGNUM:
95
- {
96
- LWES_IP_ADDR *addr = ALLOC(LWES_IP_ADDR); /* never fails */
97
- int rv;
98
-
99
- addr->s_addr = htonl(NUM2UINT(val));
100
- rv = lwes_event_set_IP_ADDR(event, name, *addr);
101
-
102
- if (rv < 0)
103
- xfree(addr);
104
- return rv;
105
- }
105
+ addr.s_addr = htonl(NUM2UINT(val));
106
+ break;
106
107
  default:
107
108
  rb_raise(rb_eTypeError,
108
109
  ":ip_addr address must be String or Integer: %s",
109
- RSTRING_PTR(rb_inspect(val)));
110
+ RAISE_INSPECT(val));
110
111
  }
112
+ lwesrb_dump_type(LWES_IP_ADDR_TOKEN, buf, off);
113
+ return marshall_IP_ADDR(addr, buf, MAX_MSG_SIZE, off);
111
114
  }
112
115
 
113
116
  /* simple type => function dispatch map */
114
117
  static struct _type_fn_map {
115
118
  ID type;
116
- int (*fn)(struct lwes_event *, LWES_CONST_SHORT_STRING, VALUE);
119
+ int (*fn)(VALUE, LWES_BYTE_P, size_t *);
117
120
  } type_fn_map[] = {
118
- #define SYMFN(T) { (ID)&sym_##T, set_##T }
121
+ #define SYMFN(T) { (ID)&sym_##T, dump_##T }
119
122
  SYMFN(uint16),
120
123
  SYMFN(int16),
121
124
  SYMFN(uint32),
@@ -126,39 +129,47 @@ static struct _type_fn_map {
126
129
  #undef SYMFN
127
130
  };
128
131
 
129
- int lwesrb_event_set_num(
130
- struct lwes_event *event,
131
- LWES_CONST_SHORT_STRING name,
132
+ /* used for Struct serialization where types are known ahead of time */
133
+ static int dump_num(
132
134
  LWES_TYPE type,
133
- VALUE val)
135
+ VALUE val,
136
+ LWES_BYTE_P buf,
137
+ size_t *off)
134
138
  {
135
139
  switch (type) {
136
- case LWES_TYPE_U_INT_16: return set_uint16(event, name, val);
137
- case LWES_TYPE_INT_16: return set_int16(event, name, val);
138
- case LWES_TYPE_U_INT_32: return set_uint32(event, name, val);
139
- case LWES_TYPE_INT_32: return set_int32(event, name, val);
140
- case LWES_TYPE_U_INT_64: return set_uint64(event, name, val);
141
- case LWES_TYPE_INT_64: return set_int64(event, name, val);
142
- case LWES_TYPE_IP_ADDR: return set_ip_addr(event, name, val);
140
+ case LWES_TYPE_U_INT_16: return dump_uint16(val, buf, off);
141
+ case LWES_TYPE_INT_16: return dump_int16(val, buf, off);
142
+ case LWES_TYPE_U_INT_32: return dump_uint32(val, buf, off);
143
+ case LWES_TYPE_INT_32: return dump_int32(val, buf, off);
144
+ case LWES_TYPE_U_INT_64: return dump_uint64(val, buf, off);
145
+ case LWES_TYPE_INT_64: return dump_int64(val, buf, off);
146
+ case LWES_TYPE_IP_ADDR: return dump_ip_addr(val, buf, off);
143
147
  default:
144
148
  rb_raise(rb_eRuntimeError,
145
149
  "unknown LWES attribute type: 0x%02x", type);
146
150
  }
147
- assert("you should never get here (set_field)");
151
+ assert("you should never get here (dump_num)");
148
152
  return -1;
149
153
  }
150
154
 
155
+ void lwesrb_dump_num(LWES_BYTE type, VALUE val, LWES_BYTE_P buf, size_t *off)
156
+ {
157
+ if (dump_num(type, val, buf, off) > 0)
158
+ return;
159
+ rb_raise(rb_eRuntimeError,
160
+ "dumping numeric type 0x%02x, type failed", type);
161
+ }
162
+
151
163
  /*
164
+ * used for Hash serialization
152
165
  * array contains two elements:
153
166
  * [ symbolic_type, number ]
154
167
  * returns the return value of the underlying lwes_event_set_* call
155
168
  */
156
- int lwesrb_event_set_numeric(
157
- struct lwes_event *event,
158
- LWES_CONST_SHORT_STRING name,
159
- VALUE array)
169
+ void lwesrb_dump_num_ary(VALUE array, LWES_BYTE_P buf, size_t *off)
160
170
  {
161
- int i;
171
+ volatile VALUE raise_inspect;
172
+ int i, rv;
162
173
  struct _type_fn_map *head;
163
174
  VALUE *ary;
164
175
  ID type;
@@ -173,15 +184,19 @@ int lwesrb_event_set_numeric(
173
184
 
174
185
  i = sizeof(type_fn_map) / sizeof(type_fn_map[0]);
175
186
  for (head = type_fn_map; --i >= 0; head++) {
176
- if (head->type == type)
177
- return head->fn(event, name, ary[1]);
178
- }
187
+ if (head->type != type)
188
+ continue;
179
189
 
180
- rb_raise(rb_eArgError,
181
- "unknown type: %s",
182
- RSTRING_PTR(rb_inspect(type)));
190
+ rv = head->fn(ary[1], buf, off);
191
+ if (rv > 0)
192
+ return;
183
193
 
184
- return -1;
194
+ rb_raise(rb_eRuntimeError,
195
+ "dumping numeric type %s, type failed",
196
+ RAISE_INSPECT(type));
197
+ }
198
+
199
+ rb_raise(rb_eArgError, "unknown type: %s", RAISE_INSPECT(type));
185
200
  }
186
201
 
187
202
  void lwesrb_init_numeric(void)
data/ext/lwes/type_db.c CHANGED
@@ -103,11 +103,12 @@ struct lwes_event_type_db * lwesrb_get_type_db(VALUE self)
103
103
  struct _tdb *tdb;
104
104
 
105
105
  Data_Get_Struct(self, struct _tdb, tdb);
106
- if (!tdb->db)
106
+ if (! tdb->db) {
107
+ volatile VALUE raise_inspect;
107
108
  rb_raise(rb_eRuntimeError,
108
- "couldn't get lwes_type_db from %s",
109
- RSTRING_PTR(rb_inspect(self)));
110
-
109
+ "couldn't get lwes_type_db from %s",
110
+ RAISE_INSPECT(self));
111
+ }
111
112
  return tdb->db;
112
113
  }
113
114
 
data/lib/lwes.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module LWES
2
- # version of our library, currently 0.3.1
3
- VERSION = "0.3.1"
2
+ # version of our library, currently 0.4.0
3
+ VERSION = "0.4.0"
4
4
 
5
5
  autoload :TypeDB, "lwes/type_db"
6
6
  autoload :Struct, "lwes/struct"
data/lib/lwes/struct.rb CHANGED
@@ -95,9 +95,21 @@ module LWES
95
95
  tmp.const_set :NAME, name.to_s
96
96
  ed = tmp.const_set :EVENT_DEF, {}
97
97
  event_def.each { |(field,type)| ed[field] = type }
98
- type_list = event_def.map { |(field,type)| [ field, field.to_s, type ] }
98
+
99
+ # freeze since emitter.c can segfault if this ever changes
100
+ type_list = event_def.map do |(field,type)|
101
+ [ field, field.to_s.freeze, type ].freeze
102
+ end.freeze
99
103
  tmp.const_set :TYPE_LIST, type_list
100
104
 
105
+ aref_map = tmp.const_set :AREF_MAP, {}
106
+ type_list.each_with_index do |(field_sym,field_str,_),idx|
107
+ aref_map[field_sym] = aref_map[field_str] = idx
108
+ end
109
+
110
+ tmp.const_set :HAVE_ENCODING,
111
+ type_list.include?([ :enc, 'enc', LWES::INT_16 ])
112
+
101
113
  defaults = options[:defaults] || {}
102
114
  defaults = tmp.const_set :DEFAULTS, defaults.dup
103
115
  tmp.class_eval(&block) if block_given?
@@ -122,6 +134,38 @@ class ::#{tmp.name}
122
134
  end
123
135
  end
124
136
  EOS
137
+
138
+ # avoid linear scans for large structs, not sure if 50 is a good enough
139
+ # threshold but it won't help for anything <= 10 since Ruby (or at least
140
+ # MRI) already optimizes those cases
141
+ if event_def.size > 50
142
+ eval <<EOS
143
+ class ::#{tmp.name}
144
+ alias __aref []
145
+ alias __aset []=
146
+ def [](key)
147
+ __aref(key.kind_of?(Fixnum) ? key : AREF_MAP[key])
148
+ end
149
+
150
+ def []=(key, value)
151
+ __aset(key.kind_of?(Fixnum) ? key : AREF_MAP[key], value)
152
+ end
153
+ end
154
+ EOS
155
+ fast_methods = []
156
+ event_def.each_with_index do |(fld,type), idx|
157
+ next if idx <= 9
158
+ if idx != aref_map[fld]
159
+ raise LoadError, "event_def corrupt: #{event_def}"
160
+ end
161
+ fast_methods << "undef_method :#{fld}, :#{fld}=\n"
162
+ fast_methods << "\ndef #{fld}; __aref #{idx}; end\n"
163
+ fast_methods << "\ndef #{fld}=(val); __aset #{idx}, val ; end\n"
164
+ end
165
+
166
+ eval("class ::#{tmp.name}; #{fast_methods.join("\n")}\n end")
167
+ end
168
+
125
169
  tmp
126
170
  end
127
171
  end
data/lwes.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = %q{lwes}
3
- s.version = "0.3.1"
3
+ s.version = "0.4.0"
4
4
  s.date = Time.now
5
5
  s.authors = ["Erik S. Chang", "Frank Maritato"]
6
6
  s.email = %q{lwes-devel@lists.sourceforge.net}
data/test/test_helper.rb CHANGED
@@ -2,6 +2,7 @@ require 'pp'
2
2
  require 'tempfile'
3
3
  require 'test/unit'
4
4
  require 'lwes'
5
+ GC.stress = true if ENV["GC_STRESS"].to_i != 0
5
6
 
6
7
  unless defined?(LISTENER_DEFAULTS)
7
8
  BEFORE_DELAY = ENV['BEFORE_DELAY'] ? ENV['BEFORE_DELAY'].to_f : 0.5
@@ -99,16 +99,6 @@ class TestEmitter < Test::Unit::TestCase
99
99
  assert_equal 1, lines.grep(/int_ip = 192.168.1.1/).size
100
100
  end
101
101
 
102
- def TODO_emit_ip_addr_object
103
- emitter = LWES::Emitter.new(@options)
104
- event = { :ip => IPAddr.new("192.168.1.1") }
105
- out = lwes_listener do
106
- assert_nothing_raised { emitter.emit("IP", event) }
107
- end
108
- lines = out.readlines
109
- assert_equal 1, lines.grep(/\bip = 192.168.1.1/).size
110
- end
111
-
112
102
  def test_emit_junk
113
103
  emitter = LWES::Emitter.new(@options)
114
104
  assert_raises(ArgumentError) { emitter.emit("JUNK", :junk => %r{junk}) }
@@ -180,6 +170,48 @@ class TestEmitter < Test::Unit::TestCase
180
170
  }
181
171
  end
182
172
 
173
+ def test_emit_enc_sym
174
+ emitter = LWES::Emitter.new(@options)
175
+ tmp = {
176
+ :enc => 1,
177
+ :a => "b",
178
+ :c => "d",
179
+ }
180
+ out = lwes_listener do
181
+ assert_nothing_raised { emitter.emit("EncTest", tmp) }
182
+ end
183
+ lines = out.readlines
184
+ assert_equal 1, lines.grep(/\A\tenc = 1;\n\z/).size
185
+ assert_equal 1, lines.grep(/\A\ta = b;\n\z/).size
186
+ assert_equal 1, lines.grep(/\A\tc = d;\n\z/).size
187
+ end
188
+
189
+ def test_emit_enc_str
190
+ emitter = LWES::Emitter.new(@options)
191
+ tmp = {
192
+ :enc => 1,
193
+ :a => "b",
194
+ :c => "d",
195
+ }
196
+ out = lwes_listener do
197
+ assert_nothing_raised { emitter.emit("EncTest", tmp) }
198
+ end
199
+ lines = out.readlines
200
+ assert_equal 1, lines.grep(/\A\tenc = 1;\n\z/).size
201
+ assert_equal 1, lines.grep(/\A\ta = b;\n\z/).size
202
+ assert_equal 1, lines.grep(/\A\tc = d;\n\z/).size
203
+ end
204
+
205
+ def test_emit_huge_event
206
+ emitter = LWES::Emitter.new(@options)
207
+ tmp = {
208
+ :a => ("b" * (1024 * 1024)),
209
+ }
210
+ assert_raises(ArgumentError) do
211
+ emitter.emit("BigTest", tmp)
212
+ end
213
+ end
214
+
183
215
  def test_close
184
216
  emitter = LWES::Emitter.new(@options)
185
217
  assert_nil emitter.close
@@ -57,6 +57,7 @@ class TestStruct < Test::Unit::TestCase
57
57
  :class => :EVENT_BOOL,
58
58
  :name => :EventBool)
59
59
  assert_equal "EVENT_BOOL", b.name
60
+ assert_equal false, b.const_get(:HAVE_ENCODING)
60
61
 
61
62
  e = assert_raises(RuntimeError) {
62
63
  LWES::Struct.new(:file=>MULTI_EVENT_ESF)
@@ -84,6 +85,7 @@ class TestStruct < Test::Unit::TestCase
84
85
  assert_equal "Event1", a.name
85
86
  assert a.const_get(:TYPE_DB).instance_of?(LWES::TypeDB)
86
87
  assert a.const_get(:EVENT_DEF).instance_of?(Hash)
88
+ assert a.const_get(:HAVE_ENCODING)
87
89
  assert_equal EXPECT_DB, a.const_get(:EVENT_DEF)
88
90
  assert_equal EXPECT_LIST, a.const_get(:TYPE_LIST)
89
91
  y = a.new
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lwes
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Erik S. Chang
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2010-04-15 00:00:00 +00:00
13
+ date: 2010-04-20 00:00:00 +00:00
14
14
  default_executable:
15
15
  dependencies: []
16
16