mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-09 03:29:43 -10:00
rjson callers: read small JSON files whole instead of stat + chunked
Audit of every rjson / rxml call site's surrounding file I/O, following the codecs' decoupling. The rxml side needs nothing: its production consumers parse buffers that arrive without the adapter (logiqx through the scanner's budgeted incremental read, natt from network payloads), and the filestream adapter is used only by the sample harness and the treehash tool. On the rjson side, the large streaming consumers are already shaped right - playlist, core info cache and the explore state read through buffered (and RZIP-aware) streams with no redundant pre-open checks, cloud sync opens tolerantly with no extra stats, and the writer flushes in buffered chunks - but the small-file readers all shared one wasteful pattern: stat the path (path_is_valid), open it, let the stream adapter fstat it again for io block sizing, then read a few hundred bytes through the chunked callback machinery. Five readers convert to filestream_read_file() + rjson_open_buffer(): the runtime log (the hot one - playlist sublabels showing per-core runtime build one of these per entry), the disk index record, the two test input drivers, and the Remote RetroPad core (the latter three being the reference code this pattern kept getting copied from). One open/size/read/close per file, parse from memory, no callback crossings - and the up-front stat is gone: filestream_read_file's failure covers missing files, and path_is_valid now runs only inside the failure branch to decide between the old quiet no-file path and the old error message, so every log line and return value is preserved while the common case pays one filesystem operation less. These files are a few hundred bytes to a few KB and always parsed in full; holding them in memory for the parse is what the parser's own input buffer was already doing, minus the chunking. Verified: strict declaration-placement gates clean on the C89 TUs; the net-retropad translation unit syntax-checked standalone; full Linux build links with HAVE_QT=1; no rjson_open_filestream readers remain outside the write-side handles the buffered writer still streams through.
This commit is contained in:
1 parent
b4eb9622df
commit
1dfed08090
5 files changed
+91
-77
No files matched your search
@@ -341,31 +341,31 @@ static bool input_test_file_read(const char* file_path)
|
||||
{
|
||||
bool success = false;
|
||||
ITifJSONContext context = {0};
|
||||
RFILE *file = NULL;
|
||||
uint8_t *file_buf = NULL;
|
||||
int64_t file_len = 0;
|
||||
rjson_t* parser;
|
||||
|
||||
/* Sanity check */
|
||||
if ( (!file_path || !*file_path)
|
||||
|| !path_is_valid(file_path)
|
||||
)
|
||||
if (!file_path || !*file_path)
|
||||
return false;
|
||||
|
||||
/* Attempt to open test input file */
|
||||
file = filestream_open(
|
||||
file_path,
|
||||
RETRO_VFS_FILE_ACCESS_READ,
|
||||
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||
|
||||
if (!file)
|
||||
/* Read the whole file in one operation: it is tiny and always
|
||||
* parsed in full, so a single open/size/read/close beats a
|
||||
* pre-open stat plus the chunked callback path (which itself
|
||||
* sizes the stream with an extra fstat). The stat below runs
|
||||
* only to classify a failure. */
|
||||
if (filestream_read_file(file_path,
|
||||
(void**)&file_buf, &file_len) < 0)
|
||||
{
|
||||
NETRETROPAD_CORE_PREFIX(log_cb)(RETRO_LOG_ERROR,
|
||||
"[Remote RetroPad] Failed to open test input file: \"%s\".\n",
|
||||
file_path);
|
||||
if (path_is_valid(file_path))
|
||||
NETRETROPAD_CORE_PREFIX(log_cb)(RETRO_LOG_ERROR,
|
||||
"[Remote RetroPad] Failed to open test input file: \"%s\".\n",
|
||||
file_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Initialise JSON parser */
|
||||
if (!(parser = rjson_open_filestream(file)))
|
||||
if (!(parser = rjson_open_buffer(file_buf, (size_t)file_len)))
|
||||
{
|
||||
NETRETROPAD_CORE_PREFIX(log_cb)(RETRO_LOG_ERROR,
|
||||
"[Remote RetroPad] Failed to create JSON parser.\n");
|
||||
@@ -411,8 +411,8 @@ end:
|
||||
if (context.message)
|
||||
free(context.message);
|
||||
|
||||
/* Close log file */
|
||||
filestream_close(file);
|
||||
/* Release file contents */
|
||||
free(file_buf);
|
||||
|
||||
if (last_test_step >= MAX_TEST_STEPS)
|
||||
{
|
||||
|
||||
+19
-17
@@ -106,7 +106,8 @@ static bool disk_index_file_read(disk_index_file_t *disk_index_file)
|
||||
const char *file_path = NULL;
|
||||
bool success = false;
|
||||
DCifJSONContext context = {0};
|
||||
RFILE *file = NULL;
|
||||
uint8_t *file_buf = NULL;
|
||||
int64_t file_len = 0;
|
||||
rjson_t* parser;
|
||||
|
||||
/* Sanity check */
|
||||
@@ -115,27 +116,28 @@ static bool disk_index_file_read(disk_index_file_t *disk_index_file)
|
||||
|
||||
file_path = disk_index_file->file_path;
|
||||
|
||||
if ( (!file_path || !*file_path)
|
||||
|| !path_is_valid(file_path)
|
||||
)
|
||||
if (!file_path || !*file_path)
|
||||
return false;
|
||||
|
||||
/* Attempt to open disk index file */
|
||||
file = filestream_open(
|
||||
file_path,
|
||||
RETRO_VFS_FILE_ACCESS_READ,
|
||||
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||
|
||||
if (!file)
|
||||
/* Read the whole record in one operation: these files are tiny
|
||||
* and always parsed in full, so a single open/size/read/close
|
||||
* beats a pre-open stat plus the chunked callback path (which
|
||||
* itself sizes the stream with an extra fstat). Most content
|
||||
* has no disk index record - that common case is one failed
|
||||
* open, and the stat runs only to classify a failure as worth
|
||||
* logging. */
|
||||
if (filestream_read_file(file_path,
|
||||
(void**)&file_buf, &file_len) < 0)
|
||||
{
|
||||
RARCH_ERR(
|
||||
"[Disk index file] Failed to open disk index record file: \"%s\".\n",
|
||||
file_path);
|
||||
if (path_is_valid(file_path))
|
||||
RARCH_ERR(
|
||||
"[Disk index file] Failed to open disk index record file: \"%s\".\n",
|
||||
file_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Initialise JSON parser */
|
||||
if (!(parser = rjson_open_filestream(file)))
|
||||
if (!(parser = rjson_open_buffer(file_buf, (size_t)file_len)))
|
||||
{
|
||||
RARCH_ERR("[Disk index file] Failed to create JSON parser.\n");
|
||||
goto end;
|
||||
@@ -190,8 +192,8 @@ end:
|
||||
if (context.image_path)
|
||||
free(context.image_path);
|
||||
|
||||
/* Close log file */
|
||||
filestream_close(file);
|
||||
/* Release file contents */
|
||||
free(file_buf);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
+18
-16
@@ -187,33 +187,35 @@ static bool input_test_file_read(const char* file_path)
|
||||
{
|
||||
bool success = false;
|
||||
KTifJSONContext context = {0};
|
||||
RFILE *file = NULL;
|
||||
uint8_t *file_buf = NULL;
|
||||
int64_t file_len = 0;
|
||||
rjson_t* parser;
|
||||
|
||||
/* Sanity check */
|
||||
if ( (!file_path || !*file_path)
|
||||
|| !path_is_valid(file_path)
|
||||
)
|
||||
if (!file_path || !*file_path)
|
||||
{
|
||||
RARCH_DBG("[Test input] No test input file supplied.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Attempt to open test input file */
|
||||
file = filestream_open(
|
||||
file_path,
|
||||
RETRO_VFS_FILE_ACCESS_READ,
|
||||
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||
|
||||
if (!file)
|
||||
/* Read the whole file in one operation: it is tiny and always
|
||||
* parsed in full, so a single open/size/read/close beats a
|
||||
* pre-open stat plus the chunked callback path (which itself
|
||||
* sizes the stream with an extra fstat). The stat below runs
|
||||
* only to classify a failure. */
|
||||
if (filestream_read_file(file_path,
|
||||
(void**)&file_buf, &file_len) < 0)
|
||||
{
|
||||
RARCH_ERR("[Test input] Failed to open test input file: \"%s\".\n",
|
||||
file_path);
|
||||
if (!path_is_valid(file_path))
|
||||
RARCH_DBG("[Test input] No test input file supplied.\n");
|
||||
else
|
||||
RARCH_ERR("[Test input] Failed to open test input file: \"%s\".\n",
|
||||
file_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Initialise JSON parser */
|
||||
if (!(parser = rjson_open_filestream(file)))
|
||||
if (!(parser = rjson_open_buffer(file_buf, (size_t)file_len)))
|
||||
{
|
||||
RARCH_ERR("[Test input] Failed to create JSON parser.\n");
|
||||
goto end;
|
||||
@@ -258,8 +260,8 @@ end:
|
||||
if (context.param_str)
|
||||
free(context.param_str);
|
||||
|
||||
/* Close log file */
|
||||
filestream_close(file);
|
||||
/* Release file contents */
|
||||
free(file_buf);
|
||||
|
||||
if (last_test_step >= MAX_TEST_STEPS)
|
||||
{
|
||||
|
||||
@@ -185,33 +185,35 @@ static bool input_test_file_read(const char* file_path)
|
||||
{
|
||||
bool success = false;
|
||||
JTifJSONContext context = {0};
|
||||
RFILE *file = NULL;
|
||||
uint8_t *file_buf = NULL;
|
||||
int64_t file_len = 0;
|
||||
rjson_t* parser;
|
||||
|
||||
/* Sanity check */
|
||||
if ( (!file_path || !*file_path)
|
||||
|| !path_is_valid(file_path)
|
||||
)
|
||||
if (!file_path || !*file_path)
|
||||
{
|
||||
RARCH_DBG("[Test joypad] No test input file supplied.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Attempt to open test input file */
|
||||
file = filestream_open(
|
||||
file_path,
|
||||
RETRO_VFS_FILE_ACCESS_READ,
|
||||
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||
|
||||
if (!file)
|
||||
/* Read the whole file in one operation: it is tiny and always
|
||||
* parsed in full, so a single open/size/read/close beats a
|
||||
* pre-open stat plus the chunked callback path (which itself
|
||||
* sizes the stream with an extra fstat). The stat below runs
|
||||
* only to classify a failure. */
|
||||
if (filestream_read_file(file_path,
|
||||
(void**)&file_buf, &file_len) < 0)
|
||||
{
|
||||
RARCH_ERR("[Test joypad] Failed to open test input file: \"%s\".\n",
|
||||
file_path);
|
||||
if (!path_is_valid(file_path))
|
||||
RARCH_DBG("[Test joypad] No test input file supplied.\n");
|
||||
else
|
||||
RARCH_ERR("[Test joypad] Failed to open test input file: \"%s\".\n",
|
||||
file_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Initialise JSON parser */
|
||||
if (!(parser = rjson_open_filestream(file)))
|
||||
if (!(parser = rjson_open_buffer(file_buf, (size_t)file_len)))
|
||||
{
|
||||
RARCH_ERR("[Test joypad] Failed to create JSON parser.\n");
|
||||
goto end;
|
||||
@@ -256,8 +258,8 @@ end:
|
||||
if (context.param_str)
|
||||
free(context.param_str);
|
||||
|
||||
/* Close log file */
|
||||
filestream_close(file);
|
||||
/* Release file contents */
|
||||
free(file_buf);
|
||||
|
||||
if (last_test_step >= MAX_TEST_STEPS)
|
||||
{
|
||||
|
||||
+19
-11
@@ -127,18 +127,26 @@ static void runtime_log_read_file(runtime_log_t *runtime_log)
|
||||
unsigned state_slot = 0;
|
||||
|
||||
RtlJSONContext context = {0};
|
||||
/* Attempt to open log file */
|
||||
RFILE *file = filestream_open(runtime_log->path,
|
||||
RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||
uint8_t *file_buf = NULL;
|
||||
int64_t file_len = 0;
|
||||
|
||||
if (!file)
|
||||
/* Read the whole log in one operation: these files are a few
|
||||
* hundred bytes and always parsed in full, so a single
|
||||
* open/size/read/close beats a pre-open stat plus the chunked
|
||||
* callback path (which itself sizes the stream with an extra
|
||||
* fstat). A missing log - the first-run case - is silent, as
|
||||
* it always was; the stat runs only when there is a failure to
|
||||
* classify. */
|
||||
if (filestream_read_file(runtime_log->path,
|
||||
(void**)&file_buf, &file_len) < 0)
|
||||
{
|
||||
RARCH_ERR("[Runtime] Failed to open runtime log file: \"%s\".\n", runtime_log->path);
|
||||
if (path_is_valid(runtime_log->path))
|
||||
RARCH_ERR("[Runtime] Failed to open runtime log file: \"%s\".\n", runtime_log->path);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Initialise JSON parser */
|
||||
if (!(parser = rjson_open_filestream(file)))
|
||||
if (!(parser = rjson_open_buffer(file_buf, (size_t)file_len)))
|
||||
{
|
||||
RARCH_ERR("[Runtime] Failed to create JSON parser.\n");
|
||||
goto end;
|
||||
@@ -315,8 +323,8 @@ end:
|
||||
if (context.state_slot)
|
||||
free(context.state_slot);
|
||||
|
||||
/* Close log file */
|
||||
filestream_close(file);
|
||||
/* Release file contents */
|
||||
free(file_buf);
|
||||
}
|
||||
|
||||
/* Initialise runtime log, loading current parameters
|
||||
@@ -485,9 +493,9 @@ runtime_log_t *runtime_log_init(
|
||||
|
||||
strlcpy(runtime_log->path, log_file_path, sizeof(runtime_log->path));
|
||||
|
||||
/* Load existing log file, if it exists */
|
||||
if (path_is_valid(runtime_log->path))
|
||||
runtime_log_read_file(runtime_log);
|
||||
/* Load existing log file, if it exists (a missing file is
|
||||
* handled - silently - inside) */
|
||||
runtime_log_read_file(runtime_log);
|
||||
|
||||
return runtime_log;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user