lwes 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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