Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
P
protobuf
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
protobuf
Commits
d6152dd5
Unverified
Commit
d6152dd5
authored
Aug 24, 2017
by
Aaron Patterson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Move parse frame array to the Map object
This makes the frame stack per-parser, and per-thread. Fixes #3250
parent
364060bb
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
42 additions
and
23 deletions
+42
-23
encode_decode.c
ruby/ext/google/protobuf_c/encode_decode.c
+2
-19
map.c
ruby/ext/google/protobuf_c/map.c
+12
-0
protobuf.c
ruby/ext/google/protobuf_c/protobuf.c
+0
-2
protobuf.h
ruby/ext/google/protobuf_c/protobuf.h
+3
-2
basic.rb
ruby/tests/basic.rb
+25
-0
No files found.
ruby/ext/google/protobuf_c/encode_decode.c
View file @
d6152dd5
...
...
@@ -280,11 +280,6 @@ rb_data_type_t MapParseFrame_type = {
{
MapParseFrame_mark
,
MapParseFrame_free
,
NULL
},
};
// Array of Ruby objects wrapping map_parse_frame_t.
// We don't allow multiple concurrent decodes, so we assume that this global
// variable is specific to the "current" decode.
VALUE
map_parse_frames
;
static
map_parse_frame_t
*
map_push_frame
(
VALUE
map
,
const
map_handlerdata_t
*
handlerdata
)
{
map_parse_frame_t
*
frame
=
ALLOC
(
map_parse_frame_t
);
...
...
@@ -293,16 +288,12 @@ static map_parse_frame_t* map_push_frame(VALUE map,
native_slot_init
(
handlerdata
->
key_field_type
,
&
frame
->
key_storage
);
native_slot_init
(
handlerdata
->
value_field_type
,
&
frame
->
value_storage
);
rb_ary_push
(
map_parse_frames
,
Map_push_frame
(
map
,
TypedData_Wrap_Struct
(
rb_cObject
,
&
MapParseFrame_type
,
frame
));
return
frame
;
}
static
void
map_pop_frame
()
{
rb_ary_pop
(
map_parse_frames
);
}
// Handler to begin a map entry: allocates a temporary frame. This is the
// 'startsubmsg' handler on the msgdef that contains the map field.
static
void
*
startmapentry_handler
(
void
*
closure
,
const
void
*
hd
)
{
...
...
@@ -336,7 +327,7 @@ static bool endmap_handler(void *closure, const void *hd, upb_status* s) {
&
frame
->
value_storage
);
Map_index_set
(
frame
->
map
,
key
,
value
);
map_pop_frame
(
);
Map_pop_frame
(
frame
->
map
);
return
true
;
}
...
...
@@ -775,10 +766,6 @@ VALUE Message_decode(VALUE klass, VALUE data) {
msg_rb
=
rb_class_new_instance
(
0
,
NULL
,
msgklass
);
TypedData_Get_Struct
(
msg_rb
,
MessageHeader
,
&
Message_type
,
msg
);
// We generally expect this to be clear already, but clear it in case parsing
// previously got interrupted somehow.
rb_ary_clear
(
map_parse_frames
);
{
const
upb_pbdecodermethod
*
method
=
msgdef_decodermethod
(
desc
);
const
upb_handlers
*
h
=
upb_pbdecodermethod_desthandlers
(
method
);
...
...
@@ -823,10 +810,6 @@ VALUE Message_decode_json(VALUE klass, VALUE data) {
msg_rb
=
rb_class_new_instance
(
0
,
NULL
,
msgklass
);
TypedData_Get_Struct
(
msg_rb
,
MessageHeader
,
&
Message_type
,
msg
);
// We generally expect this to be clear already, but clear it in case parsing
// previously got interrupted somehow.
rb_ary_clear
(
map_parse_frames
);
{
const
upb_json_parsermethod
*
method
=
msgdef_jsonparsermethod
(
desc
);
stackenv
se
;
...
...
ruby/ext/google/protobuf_c/map.c
View file @
d6152dd5
...
...
@@ -146,6 +146,7 @@ void Map_mark(void* _self) {
Map
*
self
=
_self
;
rb_gc_mark
(
self
->
value_type_class
);
rb_gc_mark
(
self
->
parse_frames
);
if
(
self
->
value_type
==
UPB_TYPE_STRING
||
self
->
value_type
==
UPB_TYPE_BYTES
||
...
...
@@ -174,6 +175,16 @@ VALUE Map_alloc(VALUE klass) {
return
TypedData_Wrap_Struct
(
klass
,
&
Map_type
,
self
);
}
VALUE
Map_push_frame
(
VALUE
map
,
VALUE
val
)
{
Map
*
self
=
ruby_to_Map
(
map
);
return
rb_ary_push
(
self
->
parse_frames
,
val
);
}
VALUE
Map_pop_frame
(
VALUE
map
)
{
Map
*
self
=
ruby_to_Map
(
map
);
return
rb_ary_pop
(
self
->
parse_frames
);
}
static
bool
needs_typeclass
(
upb_fieldtype_t
type
)
{
switch
(
type
)
{
case
UPB_TYPE_MESSAGE
:
...
...
@@ -227,6 +238,7 @@ VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
self
->
key_type
=
ruby_to_fieldtype
(
argv
[
0
]);
self
->
value_type
=
ruby_to_fieldtype
(
argv
[
1
]);
self
->
parse_frames
=
rb_ary_new
();
// Check that the key type is an allowed type.
switch
(
self
->
key_type
)
{
...
...
ruby/ext/google/protobuf_c/protobuf.c
View file @
d6152dd5
...
...
@@ -112,6 +112,4 @@ void Init_protobuf_c() {
upb_def_to_ruby_obj_map
=
rb_hash_new
();
rb_gc_register_address
(
&
upb_def_to_ruby_obj_map
);
map_parse_frames
=
rb_ary_new
();
rb_gc_register_address
(
&
map_parse_frames
);
}
ruby/ext/google/protobuf_c/protobuf.h
View file @
d6152dd5
...
...
@@ -166,8 +166,6 @@ extern VALUE cBuilder;
extern
VALUE
cError
;
extern
VALUE
cParseError
;
extern
VALUE
map_parse_frames
;
// We forward-declare all of the Ruby method implementations here because we
// sometimes call the methods directly across .c files, rather than going
// through Ruby's method dispatching (e.g. during message parse). It's cleaner
...
...
@@ -397,6 +395,7 @@ typedef struct {
upb_fieldtype_t
key_type
;
upb_fieldtype_t
value_type
;
VALUE
value_type_class
;
VALUE
parse_frames
;
upb_strtable
table
;
}
Map
;
...
...
@@ -405,6 +404,8 @@ void Map_free(void* self);
VALUE
Map_alloc
(
VALUE
klass
);
VALUE
Map_init
(
int
argc
,
VALUE
*
argv
,
VALUE
self
);
void
Map_register
(
VALUE
module
);
VALUE
Map_push_frame
(
VALUE
self
,
VALUE
val
);
VALUE
Map_pop_frame
(
VALUE
self
);
extern
const
rb_data_type_t
Map_type
;
extern
VALUE
cMap
;
...
...
ruby/tests/basic.rb
View file @
d6152dd5
...
...
@@ -96,8 +96,18 @@ module BasicTest
optional
:d
,
:enum
,
4
,
"TestEnum"
end
end
add_message
"repro.Outer"
do
map
:items
,
:int32
,
:message
,
1
,
"repro.Inner"
end
add_message
"repro.Inner"
do
end
end
Outer
=
pool
.
lookup
(
"repro.Outer"
).
msgclass
Inner
=
pool
.
lookup
(
"repro.Inner"
).
msgclass
Foo
=
pool
.
lookup
(
"Foo"
).
msgclass
Bar
=
pool
.
lookup
(
"Bar"
).
msgclass
Baz
=
pool
.
lookup
(
"Baz"
).
msgclass
...
...
@@ -675,6 +685,21 @@ module BasicTest
m
.
map_string_int32
[
'aaa'
]
=
3
end
def
test_concurrent_decoding
o
=
Outer
.
new
o
.
items
[
0
]
=
Inner
.
new
raw
=
Outer
.
encode
(
o
)
thds
=
2
.
times
.
map
do
Thread
.
new
do
100000
.
times
do
assert_equal
o
,
Outer
.
decode
(
raw
)
end
end
end
thds
.
map
(
&
:join
)
end
def
test_map_encode_decode
m
=
MapMessage
.
new
(
:map_string_int32
=>
{
"a"
=>
1
,
"b"
=>
2
},
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment