HackerReposA FIELD GUIDE TO OPEN SOURCE
ProSponsor the shelf♧ 0
← Back to top all-time
haberman
upb
C2011–2015
haberman / upb

upb

a small protobuf implementation in C

4Distinct people
19Mentions
0Explicit recommenders
69GitHub stars
REPOSITORY AT A GLANCE

What to know before exploring

What it is

a small protobuf implementation in C

GitHub

Where it is used

No documented product use has been verified yet.

What people are saying

No recommendation phrase was found in the indexed comments.

No classified warning is attached to this page. Read the discussions before treating silence as approval.

Also in these discussions

No other repository is repeatedly linked in the same discussions.

This week on Hacker News

Nov 7–Nov 14 UTC · Direct repository links and separately labeled related project stories. Indexed through 11/14/2026, 3:56:07 PM UTC.

No direct repository links were found in the indexed HN discussions over the past seven days. Older discussions are available below.

Mentions over time

HN mentions by year19 dated mentions

Observed mentions: 2011-01-09 21:27:44 UTC to 2015-04-27 16:30:59 UTC.

024682011-01-01 00:00:00 UTC to 2012-01-01 00:00:00 UTC (exclusive): 8 mentions; 0 submissions, 8 comments20112012-01-01 00:00:00 UTC to 2013-01-01 00:00:00 UTC (exclusive): 7 mentions; 0 submissions, 7 comments2013-01-01 00:00:00 UTC to 2014-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments20132014-01-01 00:00:00 UTC to 2015-01-01 00:00:00 UTC (exclusive): 3 mentions; 0 submissions, 3 comments2015-01-01 00:00:00 UTC to 2016-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2015

Counts come from the repository’s dated source evidence. Index cutoff: 2026-11-02 08:16:59 UTC.

View mention counts and date ranges
UTC ranges include their start and exclude their end. Select a period to filter the source evidence.
PeriodStart (UTC)End (exclusive, UTC)MentionsSubmissionsComments
20112011-01-01 00:00:00 UTC2012-01-01 00:00:00 UTC808
20122012-01-01 00:00:00 UTC2013-01-01 00:00:00 UTC707
20132013-01-01 00:00:00 UTC2014-01-01 00:00:00 UTC000
20142014-01-01 00:00:00 UTC2015-01-01 00:00:00 UTC303
20152015-01-01 00:00:00 UTC2016-01-01 00:00:00 UTC101

What Hacker News says

19 sources
I don't know enough about how Rc is used to know if this is an acceptable possibility, I just wanted to mention it in case it is possibly helpful. I developed a reference-counting system in my library "upb" that handles cycles and never leaks objects. It is precise for no-longer-mutable objects (objects which may no longer change the set of other refcounted objects pointed to) and less precise for mutable objects. The basic idea is to reference-count groups of objects instead of single objects, and define the groups such that no reference cycle spans groups. If you introduce a link between two refcounted objects A -> B, then A and B's groups are merged. Now refs/unrefs of A or B ref/unref the (merged) group. Nothing in the group is freed until both A and B's refcounts both fall to zero. This conservative group-merging whenever you cre
Read the rest
ate a link ensures that no reference cycle spans groups. This is imprecise and relatively wasteful if the group grows really large. But you can make it totally precise for any subgraph of refcounted objects that you're willing to freeze. At freeze time, compute strongly-connected components, and each SCC becomes a refcounted group. For any frozen subgraphs, the refcounting is totally precise. And unfrozen objects can reference frozen ones (but not the other way around). If your application ends up freezing most of the graph, this works great. Or if you're ok with the collection being pretty coarse for your groups of objects, it also works great. If you have an application that can't freeze the graph and wants pretty precise collection, this doesn't work so well. More info about my scheme is in comments in these headers: https://github.com/haberman/upb/blob/master/upb/refcounted.h https://github.com/haberman/upb/blob/master/upb/refcounted.c I always was curious if the semantics of this scheme would play nicely with the ownership system in Rust.
In Pre-Pooping Your Pants with Rust
Makes sense. If anyone is interested, I think it could be interesting to see if the refcounting approach I developed for handling cyclic references in my library "upb" would work as a Rust library: https://github.com/haberman/upb/blob/master/upb/refcounted.h The basic idea is that you refcount groups of objects instead of refcounting objects independently. You compute the groups dynamically such that no cycle can span groups. This is sort of like an arena, except that no arena is ever explicitly created, and the collection can be more precise than an arena. In my library, objects go through a two-phase lifecycle. First they are mutable, then they are frozen, after which no further mutations can be made. When an object is frozen, its outbound pointers are also frozen. The nice property of this scheme is that you can perfectly compute t
Read the rest
hese "virtual arenas" by computing strongly-connected components at freeze time. This makes the scheme optimal for frozen objects. For mutable objects, the groups are computed more conservatively and objects may not get freed as often as they otherwise would with a perfect scheme (ie. the same downside of an arena). I would love to know how this scheme might possibly be modeled in Rust. Since Rust also has strong semantics around mutability and immutability, it seems possible that a very nice idiomatic Rust interface could be implemented around this scheme, giving more precise cleanup than an arena while still allowing circular structures.
In The Road to Rust 1.0
As someone who has been working on parsing/serialization for many years, I can absolutely confirm that generating schema-specific code will beat generic code almost every time. The article discovers an important tradeoff: speed vs. convenience. Generated code is faster but less convenient, because it adds steps to your compile. And you pay this compile-time overhead for every message type you want to manipulate. The pain of this generated code was one of Kenton Varda's motivations for creating Cap'n Proto after working on Protocol Buffers for years. Unlike Protocol Buffers, Cap'n Proto doesn't need to generate parsing/serialization code because its serialization format also works as an in-memory format. I have taken a somewhat different approach to the problem, with my Protocol Buffer / JSON / etc. serialization framework upb (https:/
Read the rest
/github.com/haberman/upb). Instead of using static code generation, I use a JIT approach where I generate specialized code on-the-fly. This approach is particularly important when you are wrapping the library in an interpreted language like Python/Ruby/Lua/JavaScript, because users of these languages don't have a compile cycle at all, so adding one is a large inconvenience. My library isn't ready for prime time but I'm hoping to have something ready to use this year.
In Show HN: ffjson: faster json serialization in Go
Wow, you read a way more argumentative tone into my comment than I intended. It's all good, I'm trying to expand my understanding. :) Though I'm not sure I agree with your characterization of my points as "nonsense." > [Inline-threaded dispatch] gives a 20% speed boost, for a few dozen lines of code. Hardly "limited usefulness". Unless I'm missing something, I think you would be very hard-pressed to generate basic blocks of native code in only a few dozen lines of platform-dependent code. I'm not seeing how you could do it without implementing your own code generator (which would take far more than a dozen lines). Is there some clever way of leveraging the C compiler's output that I'm missing? Also, once you are generating basic blocks of native code, I would consider it a JIT at that point, even if it is not as sophisticated as a JIT
Read the rest
that's doing register allocation and optimization. Writing this sort of JIT that uses a static register allocation and a fixed instruction sequence for each bytecode op doesn't seem that much more work than writing an interpreter in assembly language (especially if you use Mike Pall's excellent framework DynASM: http://luajit.org/dynasm.html). > Its certainly common to use a single indirect branch. However, it is suboptimal. I don't believe that a single indirect branch is a priori slower; while replicated dispatch makes better use of the branch predictor, it also results in less optimal i-cache usage (the LuaJIT code notes this trade-off, but observes that replicated dispatch is 20-30% faster in practice: http://repo.or.cz/w/luajit-2.0.git/blob/2ad9834df6fe47c7150d...). I'm not saying switch is better, what I'm saying is that you can't reliably replicate dispatch in C (at least according to Mike's message that I cited earlier), which makes switch() a totally reasonable choice for interpreters written in C. By the way, I'm not just making stuff up, I have written a JIT of my own: https://github.com/haberman/upb/blob/master/upb/pb/decoder_x...
In Speeding up PHP with the HipHop VM
> Aside: To anyone implementing protocols -- _Please_ keep your parsers, state machines and transports as loosely coupled as possible. I, and many people I know, will love you for it. Ok, I have to curb my excitement here a bit, because what I'm about to tell you is that I'm solving exactly your problem with an obsessive focus on achieving exactly what you desire. Though in saying so I'll have to disagree with you slightly when you say: > Simple on one axis may complicate things on another, and in irreconcilable ways. Basically I'm striving for (and believe I am on the verge of achieving) a design that achieves the best possible simplicity for network parsers and serializers in all dimensions. If you're wondering what the catch is, the catch is that it's taken me 2.5 years and counting to refine the design to the point where it can achie
Read the rest
ve this. My library performs no I/O (it's buffers in, buffers out), is completely resumable (so you can suspend the state machine at any point and resume it later), is completely composable (so you can create pipelines that feed the output of one parser to the input of another), loosely coupled, small (<5k loc in the core library), easy to bind to high-level languages, minimal enough that it can run inside the Linux kernel, and FAST (can parse protocol buffers at almost 1.5GB/second). And it's open-source. Don't be misled by the fact that it's advertised as a Protocol Buffer library; that's how it started, but I'm working on generalizing it to be capable of arbitrary parsing and serializing. Though Protocol Buffers schemas are used to specify the structure of any structured data that a parser wants to produce or a serializer wants to consume. https://github.com/haberman/upb/wiki
In We Who Value Simplicity Have Built Incomprehensible Machines
I struggled with a similar question for my low-level protobuf library UPB (https://github.com/haberman/upb). Here are some blog posts describing my dilemma about this: http://blog.reverberate.org/2009/11/porting-upb-to-c.html http://blog.reverberate.org/2009/12/torn-over-c-question.htm... I ultimately chose to stick with C, and I'm happy with my decision. When people ask me why I stuck with C, it's difficult to give a single overwhelming reason why C is better. The most clear-cut one is that C++ is not supported in the Linux kernel and I want my library to be usable there. But the other reasons why I prefer C are not as easy to quantify. One reason is that code written in C is more transparent. You can look at some C and know what it is going to do (add some numbers, call a function, etc). Macros are the one exception to this, but
Read the rest
good C programs use these sparingly and clearly mark the macro with an UPPER_CASE_IDENTIFIER. C++ is much harder to "see through." Any function call could end up throwing an exception which does a non-local exit from the function. Any addition, assignment, pointer dereference, etc could actually be an overloaded operator. Any function call could be performing a user-defined implicit conversion on any of its parameters. For overloaded functions, the compiler decides what function is actually called by applying non-trivial pattern matching rules. The runtime will automatically invoke any static initialization code (like constructors of global statics) pre-main in an undefined order. etc. etc. I intend to get a thorough security review of my library once its design stabilizes. I asked Tavis Ormandy (a fellow Googler and security badass) which language is easier to audit for security and he said C for the reasons of transparency I listed above. People often say that you can just avoid using the parts of C++ that you don't like. That is true, but hard to enforce, especially on a multi-person project. If you're asking others to follow your set of rules, you have to write those rules down in meticulous detail, leading to something like the Google C++ style guide (http://google-styleguide.googlecode.com/svn/trunk/cppguide.x...), and at that point you're asking your contributors to study and internalize a large and complicated list of what is and isn't allowed just for the privilege of contributing to your project. I don't think this approach scales to lots of projects that are all choosing a different subset of C++. There are definitely things I miss by not having C++'s facilities. Constructors and an implicit "this" parameter are both really nice. Constructors are remarkable in that you can write a single function that gives you three different construction patterns for free (direct construction, heap construction with "new", construction in an arbitrary location with placement new). Automatic upcasts are nice and totally safe. Inheritance and public/private specifiers let you express directly lots of things you can only express with comments in C. But overall I think that using straight C is the right choice for a project like my library UPB.
In Why should I have written ZeroMQ in C, not C++
Right now there is a divide among programmers. One one side you have people like the author who crave the power of code-as-data more than they care about nice syntax and therefore love Lisp. On the other side you have people who like more conventional syntax more than they care about code-as-data and therefore don't love Lisp. Neither side can understand the other: one side says "why do you resist ultimate power?" and the other side says "how can you possibly think that your code is readable?" My belief (and what I am starting to consider my life's work) is that the gap can be bridged. Lisp's power comes from treating code as data. But all code becomes data eventually; turning code into data is exactly what parsers do, and every language has a parser. The author says "it's about read," but "read" (in his example) is just a parser. Th
Read the rest
e author asks "How would you do that in Python?" The answer is that it would be something like this: import ast class MyTransformer(ast.NodeTransformer): pass # Implement transformation logic here. node = MyTransformer().visit(ast.parse("x = 1")) print ast.dump(node) This works alright, but what I'm after is a more universal solution. With syntax trees there's a lot of support functionality you frequently want: a way to specify the schema of the tree, convenient serialization/deserialization, and ideally a solution that is not specific to any one programming language. My answer to this question might surprise some people, but after spending a lot of time thinking about this problem, I'm quite convinced of it. The answer is Protocol Buffers. It's true that Protocol Buffers were originally designed for network messaging, but they turn out to be an incredibly solid foundation on which to build general-purpose solutions for specifying and manipulating trees of strongly-typed data without being tied to any one programing language. Just look at a system like http://scottmcpeak.com/elkhound/sources/ast/index.html that was specifically designed to store AST's and look how similar it is to .proto files. (As an aside, programmers have spent the last 15 years or so attempting to use XML in this role of "generic language-independent tree structured serialization format," but it wasn't the right fit because most data is not markup. Protocol Buffers can deliver on everything people wanted XML to be). Why should manipulating syntax trees require us to write in syntax trees? The answer is that it shouldn't, but this is non-obvious because of how inconvenient parsers currently are to use. One of my life's goals is to help change that. If you find this intriguing, please feel free to follow: https://github.com/haberman/upb/wiki https://github.com/haberman/gazelle
In Lisp: It's Not About Macros, It's About Read
> The idea that Amazon has cycle-optimized network parsing code, and that they did it for a significant practical benefit... I have no reason to doubt you, but I'd like to hear more. I can speak better to Google, since it's my more recent experience. Google's internal data format is Protocol Buffers (and all the code is open-sourced, as you probably know). The C++ code that is generated to parse Protocol Buffers is fast (on the order of hundreds of MB/s) as a result of a lot of optimization. This has reached a rough ceiling of what I believe is possible with this approach (generated C++). Even so, Protocol Buffer parsing code shows up in company-wide CPU profiles, and certain teams in particular have performance issues where Protocol Buffer parsing is a significant concern for them. To address these issues, I wrote a Protocol Buffer p
Read the rest
arser that improves performance in two ways: - it is an event-based parser (like SAX) instead of the protobuf generated classes which are a more DOM-like approach (always parsing into a tree of data structures). With my parser you bind fields to callbacks, and you can parse into any data structure (or do pure stream processing). - I wrote a JIT compiler that can translate a Protocol Buffer schema directly into x86-64 machine code that parses that schema. Without the intermediate C++ step, I can generate better machine code than the C++ compiler does. In an apples-to-apples test, I beat the generated C++ by 10-40%. If you do more pure stream parsing the win is even greater. My protobuf work is open source: https://github.com/haberman/upb > I'm not sure I could have won much by counting the cycles it took me to pull (say) an NBO integer out of a packet. That's certainly different experience than mine. I don't know much about routers.
In ISO C is increasingly moronic
Indeed. Here's how from the command line: protoc -o schema.pb schema.proto The meta-schema for compiled .proto files can be found here [1]. In fact, I know of several protobuf implementations [2] [3] that avoid parsing .proto files by working with their compiled message form. I use protobuf as a storage format for record streams. It's nice for binary data (documents, images, thumbnails, etc) where JSON string escaping would be wasteful. Each protobuf record in the file is preceded by a length and a magic number specifying record type, and the first record in the file embeds the compiled .proto schema. This means it's possible to read and work with a record stream without specifying the schema separately, and without generating any code. Disclaimer: I'm the author of the lwpb Python protobuf library. [1] http://code.google.com/p/proto
Read the rest
In Protocol Buffers, Avro, Thrift & MessagePack
> Hence it should not be surprising that PB is strongly typed, has a separate schema file, and also requires a compilation step to output the language-specific boilerplate to read and serialize messages. I've spent the last two years working on a Protocol Buffer implementation that does not have these limitations. Using my implementation upb (https://github.com/haberman/upb/wiki) you can import schema definitions at runtime (or even define your own schema using a convenient API instead of writing a .proto file), with no loss of efficiency compared to pre-compiled solutions. (My implementation isn't quite usable yet, but I'm working on a Lua extension as we speak). I'm also working on making it easy to parse JSON into protocol buffer data structures, so that in cases where JSON is de facto typed (which I think is quite often the case) yo
Read the rest
u can use Protocol Buffers as your data analysis platform even if your on-the-wire data is JSON. The benefits are greater efficiency (protobufs can be stored as structs instead of hash tables) and convenient type checking / schema validation. This question of how to represent and serialize data in an interoperable way is a path that began with XML, evolved to JSON, and IMO will converge on a mix of JSON and Protocol Buffers. Having a schema is useful: you get evidence of this from the fact that every format eventually develops a schema language to go along with it (XML Schema, JSON Schema). Protocol Buffers hit a sweet spot between simplicity and capability with its schema definition. Once you have defined a data model and a schema language, serialization formats are commodities. Protocol Buffer binary format and JSON just happen to be two formats that can both serialize trees of data that conform to a .proto file. On the wire they have different advantages/disadvantages (size, parsing speed, human readability) but once you've decoded them into data structures the differences between them can disappear. If you take this idea even farther, you can consider column-striped databases to be just another serialization format for the same data. For example, the Dremel database described by Google's paper (http://static.googleusercontent.com/external_content/untrust...) also uses Protocol Buffers as its native schema, so your core analysis code could be written to iterate over either row-major logfiles or a column-major database like Dremel without having to know the difference, because in both cases you're just dealing with Protocol Buffer objects. I think this is an extremely powerful idea, and it is the reason I have put so much work into upb. To take this one step further, I think that Protocol Buffers also represent parse trees very well: you can think of a domain-specific language as a human-friendly serialization of the parse tree for that DSL. You can really nicely model text-based protocols like HTTP as Protocol Buffer schemas: message HTTPRequest { enum Action { GET = 0; POST = 1; // ... } optional Action action = 1; optional string url = 2; message Header { optional string name = 1; optional string value = 2; } repeated Header header = 3; // ... } Everything is just trees of data structures. Protocol Buffers are just a convenient way of specifying a schema for those data structures. Parsers for both binary and text formats are just ways of turning a stream of bytes into trees of structured data.
In Protocol Buffers, Avro, Thrift & MessagePack

Showing the 15 most recent of 19 sources. Enable JavaScript to search and browse every indexed mention.

MAKE YOURSELF AT HOME

A few shortcuts

/
Search the collection
?
Open this guide
Esc
Close dialogs and navigation

Your saved repositories and interests stay in this browser.