2
2
#include < string>
3
3
#include < set>
4
4
#include < sstream>
5
+ #include < iostream>
6
+ #include < fstream>
7
+ #include < regex>
8
+ #include < climits>
5
9
6
10
extern " C" {
7
11
#include < sai.h>
@@ -10,32 +14,44 @@ extern "C" {
10
14
#include " swss/table.h"
11
15
#include " meta/sai_serialize.h"
12
16
#include " sairediscommon.h"
17
+ #include < nlohmann/json.hpp>
13
18
14
19
#include < getopt.h>
15
20
16
21
// TODO split to multiple cpp
17
22
18
23
using namespace swss ;
24
+ using json = nlohmann::json;
25
+
26
+ // Default value: 100 MB
27
+ constexpr int64_t RDB_JSON_MAX_SIZE = 1024 * 1024 * 100 ;
19
28
20
29
struct CmdOptions
21
30
{
22
31
bool skipAttributes;
23
32
bool dumpTempView;
24
33
bool dumpGraph;
34
+ std::string rdbJsonFile;
35
+ uint64_t rdbJSonSizeLimit;
25
36
};
26
37
27
- CmdOptions g_cmdOptions;
28
- std::map<sai_object_id_t , const TableMap*> g_oid_map;
38
+
39
+ static CmdOptions g_cmdOptions;
40
+ static std::map<sai_object_id_t , const TableMap*> g_oid_map;
29
41
30
42
void printUsage ()
31
43
{
32
44
SWSS_LOG_ENTER ();
33
45
34
- std::cout << " Usage: saidump [-t] [-g] [-h]" << std::endl;
46
+ std::cout << " Usage: saidump [-t] [-g] [-r] [-m] [- h]" << std::endl;
35
47
std::cout << " -t --tempView:" << std::endl;
36
48
std::cout << " Dump temp view" << std::endl;
37
49
std::cout << " -g --dumpGraph:" << std::endl;
38
50
std::cout << " Dump current graph" << std::endl;
51
+ std::cout << " -r --rdb:" << std::endl;
52
+ std::cout << " Dump by parsing the RDB JSON file, which is created by rdbtools based on Redis dump.rdb that is generated by Redis SAVE command" << std::endl;
53
+ std::cout << " -m --max:" << std::endl;
54
+ std::cout << " Config the the RDB JSON file's max size in MB, which is optional with default value 100MB" << std::endl;
39
55
std::cout << " -h --help:" << std::endl;
40
56
std::cout << " Print out this message" << std::endl;
41
57
}
@@ -48,15 +64,19 @@ CmdOptions handleCmdLine(int argc, char **argv)
48
64
49
65
options.dumpTempView = false ;
50
66
options.dumpGraph = false ;
67
+ options.rdbJSonSizeLimit = RDB_JSON_MAX_SIZE;
51
68
52
- const char * const optstring = " gth" ;
69
+ const char * const optstring = " gtr:m:h" ;
70
+ uint64_t result = 0 ;
53
71
54
72
while (true )
55
73
{
56
74
static struct option long_options[] =
57
75
{
58
76
{ " dumpGraph" , no_argument, 0 , ' g' },
59
77
{ " tempView" , no_argument, 0 , ' t' },
78
+ { " rdb" , required_argument, 0 , ' r' },
79
+ { " max" , required_argument, 0 , ' m' },
60
80
{ " help" , no_argument, 0 , ' h' },
61
81
{ 0 , 0 , 0 , 0 }
62
82
};
@@ -82,6 +102,33 @@ CmdOptions handleCmdLine(int argc, char **argv)
82
102
options.dumpTempView = true ;
83
103
break ;
84
104
105
+ case ' r' :
106
+ SWSS_LOG_NOTICE (" Dumping from %s" , optarg);
107
+ options.rdbJsonFile = std::string (optarg);
108
+ break ;
109
+
110
+ case ' m' :
111
+ if (!regex_match (optarg, std::regex (R"( [+]?\d+)" ))) // only positive numeric chars are valid, such as 3984, +3232, etc.
112
+ {
113
+ SWSS_LOG_WARN (" invalid option -m %s" , optarg);
114
+ printUsage ();
115
+ exit (EXIT_SUCCESS);
116
+ }
117
+
118
+ result = strtoull (optarg, NULL , 0 );
119
+
120
+ if ((errno == ERANGE && result == ULLONG_MAX) || result == 0 || result >= INT_MAX)
121
+ {
122
+ SWSS_LOG_WARN (" invalid option -m %s" , optarg);
123
+ printUsage ();
124
+ exit (EXIT_SUCCESS);
125
+ }
126
+
127
+ options.rdbJSonSizeLimit = result * 1024 * 1024 ;
128
+ SWSS_LOG_NOTICE (" Configure the RDB JSON MAX size to %llu MB" , options.rdbJSonSizeLimit / 1024 / 1024 );
129
+
130
+ break ;
131
+
85
132
case ' h' :
86
133
printUsage ();
87
134
exit (EXIT_SUCCESS);
@@ -399,7 +446,153 @@ void dumpGraph(const TableDump& td)
399
446
std::cout << " }" << std::endl;
400
447
}
401
448
402
- int main (int argc, char ** argv)
449
+ #define SWSS_LOG_ERROR_AND_STDERR (format, ...) { fprintf (stderr, format" \n " , ##__VA_ARGS__); SWSS_LOG_ERROR (format, ##__VA_ARGS__); }
450
+
451
+ /* *
452
+ * @brief Process the input JSON file to make sure it's a valid JSON file for the JSON library.
453
+ */
454
+ static sai_status_t preProcessFile (const std::string file_name)
455
+ {
456
+ SWSS_LOG_ENTER ();
457
+
458
+ std::ifstream input_file (file_name);
459
+
460
+ if (!input_file.is_open ())
461
+ {
462
+ SWSS_LOG_ERROR_AND_STDERR (" Failed to open the input file %s." , file_name.c_str ());
463
+ return SAI_STATUS_FAILURE;
464
+ }
465
+
466
+ input_file.seekg (0 , std::ios::end); // Move to the end of the file
467
+ uint64_t file_size = input_file.tellg (); // Get the current position
468
+ SWSS_LOG_NOTICE (" Get %s's size %" PRIu64 " Bytes, limit: %" PRIu64 " MB." , file_name.c_str (), file_size, g_cmdOptions.rdbJSonSizeLimit / 1024 / 1024 );
469
+
470
+ if (file_size >= g_cmdOptions.rdbJSonSizeLimit )
471
+ {
472
+ SWSS_LOG_ERROR_AND_STDERR (" Get %s's size failure or its size %" PRIu64 " >= %" PRIu64 " MB." , file_name.c_str (), file_size, g_cmdOptions.rdbJSonSizeLimit / 1024 / 1024 );
473
+ return SAI_STATUS_FAILURE;
474
+ }
475
+
476
+ input_file.seekg (0 ); // Move to the begin of the file
477
+
478
+ // Read the content of the input file into a string
479
+ std::string content ((std::istreambuf_iterator<char >(input_file)),
480
+ std::istreambuf_iterator<char >());
481
+
482
+ content = regex_replace (content, std::regex (" \\ },\\ {\\ r" ), " ," );
483
+
484
+ std::ofstream outputFile (file_name);
485
+
486
+ if (!outputFile.is_open ())
487
+ {
488
+ SWSS_LOG_ERROR_AND_STDERR (" Failed to open the output file %s." , file_name.c_str ());
489
+ return SAI_STATUS_FAILURE;
490
+ }
491
+
492
+ // Remove the 1st and last char to make sure its format is same as previous output
493
+ if (content.size () >= 2 && content[0 ] == ' [' && content[content.length ()-1 ] == ' ]' )
494
+ {
495
+ outputFile << content.substr (1 , content.size ()-2 );
496
+ }
497
+ else
498
+ {
499
+ outputFile << content;
500
+ }
501
+
502
+ return SAI_STATUS_SUCCESS;
503
+ }
504
+
505
+ static sai_status_t dumpFromRedisRdbJson (const std::string file_name)
506
+ {
507
+ SWSS_LOG_ENTER ();
508
+
509
+ std::ifstream input_file (file_name);
510
+
511
+ if (!input_file.is_open ())
512
+ {
513
+ SWSS_LOG_ERROR_AND_STDERR (" The file %s does not exist for dumping from Redis RDB JSON file." , file_name.c_str ());
514
+ return SAI_STATUS_FAILURE;
515
+ }
516
+
517
+ try
518
+ {
519
+ // Parse the JSON data from the file (validation)
520
+ nlohmann::json jsonData;
521
+ input_file >> jsonData;
522
+
523
+ SWSS_LOG_DEBUG (" JSON file is valid." );
524
+
525
+ for (json::iterator it = jsonData.begin (); it != jsonData.end (); ++it)
526
+ {
527
+ json jj_key = it.key ();
528
+
529
+ std::string keystr = jj_key;
530
+ std::string item_name = keystr;
531
+ size_t pos = keystr.find_first_of (" :" );
532
+
533
+ if (pos != std::string::npos)
534
+ {
535
+ if (ASIC_STATE_TABLE != keystr.substr (0 , pos)) // filter out non ASIC_STATE
536
+ {
537
+ continue ;
538
+ }
539
+
540
+ item_name = keystr.substr (pos + 1 );
541
+
542
+ if (item_name.find (" :" ) != std::string::npos)
543
+ {
544
+ item_name.replace (item_name.find_first_of (" :" ), 1 , " " );
545
+ }
546
+ }
547
+ else
548
+ {
549
+ continue ;
550
+ }
551
+
552
+ std::cout << item_name << " " << std::endl;
553
+
554
+ json jj = it.value ();
555
+
556
+ if (!it->is_object ())
557
+ {
558
+ continue ;
559
+ }
560
+
561
+ TableMap map;
562
+
563
+ for (json::iterator itt = jj.begin (); itt != jj.end (); ++itt)
564
+ {
565
+ if (itt.key () != " NULL" )
566
+ {
567
+ map[itt.key ()] = itt.value ();
568
+ }
569
+ }
570
+
571
+ constexpr size_t LINE_IDENT = 4 ;
572
+ size_t max_len = get_max_attr_len (map);
573
+ std::string str_indent = pad_string (" " , LINE_IDENT);
574
+
575
+ for (const auto &field: map)
576
+ {
577
+ std::cout << str_indent << pad_string (field.first , max_len) << " : " ;
578
+ std::cout << field.second << std::endl;
579
+ }
580
+
581
+ std::cout << std::endl;
582
+ }
583
+
584
+ return SAI_STATUS_SUCCESS;
585
+ }
586
+ catch (std::exception &ex)
587
+ {
588
+ SWSS_LOG_ERROR_AND_STDERR (" JSON file %s is invalid." , file_name.c_str ());
589
+ SWSS_LOG_ERROR_AND_STDERR (" JSON parsing error: %s." , ex.what ());
590
+ }
591
+
592
+ return SAI_STATUS_FAILURE;
593
+ }
594
+
595
+ int main (int argc, char **argv)
403
596
{
404
597
swss::Logger::getInstance ().setMinPrio (swss::Logger::SWSS_DEBUG);
405
598
@@ -411,6 +604,17 @@ int main(int argc, char ** argv)
411
604
412
605
g_cmdOptions = handleCmdLine (argc, argv);
413
606
607
+
608
+ if (g_cmdOptions.rdbJsonFile .size () > 0 )
609
+ {
610
+ if (SAI_STATUS_FAILURE == preProcessFile (g_cmdOptions.rdbJsonFile ))
611
+ {
612
+ return EXIT_FAILURE;
613
+ }
614
+
615
+ return dumpFromRedisRdbJson (g_cmdOptions.rdbJsonFile );
616
+ }
617
+
414
618
swss::DBConnector db (" ASIC_DB" , 0 );
415
619
416
620
std::string table = ASIC_STATE_TABLE;
0 commit comments