Differences from json-c
Relevant source files
The following files were used as context for generating this wiki page:
libfastjson is a fork of the json-c library, specifically designed to meet the high-performance requirements of the rsyslog project. While it maintains a significant degree of source-level compatibility, its primary objective is to provide a small, fast library focused on essential JSON handling functions rather than 100% standards compliance.
Sources: README.md:1-12
Core Philosophy and Objectives
The development of libfastjson is driven by three main goals that diverge from the original json-c trajectory:
- Reduced Footprint: Maintaining a small library by stripping away non-essential features.
- Performance: Prioritizing processing speed over strict standards adherence.
- Optimized Handling: Implementing specialized logic for common operations like string escaping and object creation to reduce CPU cycles.
Sources: README.md:4-10
API Compatibility Layer
libfastjson provides a source code compatibility layer to allow existing json-c based projects (primarily within the rsyslog family) to transition easily. This is achieved through a series of macros that map json_ prefixed functions and types to their fjson_ equivalents.
Type and Function Mapping
| json-c Type/Function | libfastjson Equivalent |
|---|---|
json_object | fjson_object |
json_bool | fjson_bool |
json_type | fjson_type |
json_object_get() | fjson_object_get() |
json_object_put() | fjson_object_put() |
json_tokener_parse() | fjson_tokener_parse() |
Sources: json_object.h:890-953
This compatibility layer can be disabled by defining FJSON_NATIVE_API_ONLY.
Sources: json_object.h:880
Architectural Improvements for Speed
Optimized String Escaping
String escaping in libfastjson utilizes a lookup table (char_needsEscape) to quickly identify characters that do not require escaping. This approach avoids complex conditional logic for the vast majority of characters (regular ASCII), resulting in a performance increase of over 30% compared to earlier iterations.
The logic minimizes CPU cycles spent in the profiler's "hot spots" during JSON serialization.
Sources: json_print.c:195-230, json_object.c:85-115
Internal Object Storage
libfastjson changed how object children are stored to reduce allocation overhead. It uses a paged structure (_fjson_child_pg) where each page contains multiple slots (FJSON_OBJECT_CHLD_PG_SIZE).
This structure allows for "page size increments" during extension, balancing memory usage against frequency of malloc calls.
Sources: json_object.h:32-42, json_object.c:215-230
Performance-Oriented API Features
Key Management Flags
libfastjson introduces specific flags for fjson_object_object_add_ex to bypass expensive operations when the developer has prior knowledge of the data:
FJSON_OBJECT_ADD_KEY_IS_NEW: Skips the check for existing keys, providing performance savings when uniqueness is guaranteed.FJSON_OBJECT_KEY_IS_CONSTANT: Prevents the library from callingstrdup()on the key. This is a "huge performance win" as it avoidsmalloc,strdup, andfreefor the key string.
Sources: json_object.h:69-93, json_object.c:303-318
Buffered Dumping
The library provides fjson_object_dump_buffered, allowing users to supply their own temporary buffer for grouping output calls. This prevents the overhead of multiple small calls to user-supplied write functions for single characters like quotes or commas.
Sources: json_print.c:450-475, json_object.h:176-193
Parsing Differences
Strict vs. Liberal Parsing
The libfastjson tokener supports a FJSON_TOKENER_STRICT flag. When not in strict mode, the parser is more liberal, following "Postel's Law":
- It accepts both single quotes (
') and double quotes (") for strings and object keys unless strict mode is enabled. - It can handle comments (
/* ... */or// ...) if strict mode is disabled. - It handles case-insensitive boolean and null values (e.g.,
True,NULL) unless strict mode explicitly forbids it.
Sources: json_tokener.c:245-280, tests/test_parse.c:165-180, tests/test_charcase.c:30-45
Number Parsing and Workarounds
libfastjson includes specific logic to detect broken sscanf implementations (often found in older or specific libc versions) and provides a manual fallback for parsing 64-bit integers (fjson_parse_int64) to ensure accuracy where standard library functions might fail or overflow incorrectly.
Sources: json_util.c:116-210
Summary
The transition from json-c to libfastjson represents a shift toward an "essentialist" JSON library. By reducing feature bloat and implementing high-performance path optimizations—specifically in string escaping, memory allocation for object members, and constant-key handling—libfastjson provides the throughput necessary for high-volume logging and data processing applications.
Sources: README.md:4-12