Foreword
Finally I have moved forward and had the first step on my new job. The most recent task is to design a Task Scheduler for assigning tasks optimally to the straddle carriers to reduce the total cost. The basic structure is to read TOS data and save it in the MySQL database and covert it to task data c++ struct in Redis. Then the Task Scheduler will read the task data and calculate a optimized assignment with genetic algorithms.
The structure sounds not that complicated but everything has its dark side. When I try to move forward I meet a lot of traps in the following parts:
- MySQL loses connection;
- Data can not be SET and GET in the correct format;
- I got confused in the usage of GAlib.
In this article I will focus on the first two bullets. For the third bullet it is worth of writting a new article to describe it.
Problem Description
For the MySQL:
- Can not reset the password;
- Can not start and show the exception message:
ERROR 2002 (HY000): Can't connect to local MySQL server through socket /var/run/mysqld/mysqld.sock' (2)
For the Redis:
- When use RPUSH to push data in the Redis, can not use GET to read the data;
- Even use SET to push, can also not use GET to read;
- Can push and read in one session, but can not read the data in another session.
Prerequisites
The environment is Ubuntu 16.04 with MySQL and Redis installed, simply use
sudo apt-get install mysql-server mysql-client
sudo apt-get install redis-server
In addition, in order to call redis in c++ , you also need hiredis installed.
Solution
Cannot Reset MySQL Password
When you install MySQL in the first time, you need to run
#root mysqladmin -u root password 'your_password'
to reset the user and password. But in my case I suffered
mysqladmin: connect to server at 'localhost' failed
error: 'Access denied for user 'root'@'localhost' (using password: NO)
To solve it, you need first stop the MySQL service and then start with safe mode
#root /etc/init.d/mysqld stop \\ Stop MySQL service
#root mysqld_safe --skip-grant-tables & \\ Start safe mode
Then you can login with root user without password
#root /usr/bin/mysql -u root -p
Enter password: \\ Here directly type enter to login
Now in the MySQL command you can reset the password
mysql> update user set password=password("your_password") where user='root' and host='localhost';
After changes you need one more command
mysql> flush privileges;
Now restart the service
#root /etc/init.d/mysqld start
and you can login with root user and the password you set.
Can not Find Sock
Sometimes you may meet the exception massage as I mentioned in the second bullet. The first thing you should do is to check the MySQL config files
/etc/my.conf
/etc/mysql/my.conf
/usr/etc/my.conf
~/.my.conf
and find
socket = /var/run/mysqld/mysqld.sock
My problem is that everytime when I restart, the mysqld.sock
will be lost. Hence, I change it with another directory and establish a soft link
#root ln -s /your_directory/mysql.sock /var/run/mysqld/mysqld.sock
then problem solved.
Redis RPUSH and GET
In hiredis, if you would like to execute a redis command, you need write in the following style
redisReply *reply = (redisReply *)redisCommand(ctx, "RPUSH %s %s", KEY_NAME, VALUE_DATA);
When I push values in a key, I use
reply = (redisReply *)redisCommand(ctx, "GET %s", KEY_NAME);
to read it but got a exception message
WRONGTYPE Operation against a key holding the wrong kind of value
this type of error is because of the mistasks of the data type. If you use
reply = (redisReply *)redisCommand(ctx, "TYPE %s", KEY_NAME);
to check the data type of the key, you may find that RPUSH will push a list but GET can only read string. To read a list, you may use
reply = (redisReply *)redisCommand(ctx, "LRANGE %s 0 -1", KEY_NAME);
cout << reply -> element[i] -> str << endl;
Actually here reply
is a pointer to a struct redisReply
. The API and usage of it can be achieved from the reference.
Redis SET and GET
As I mentioned in the previous part, you can use SET to push a string and use GET to read it. But the traps I met is, I can’t even push and read with the following format
redisReply *reply = (redisReply *)redisCommand(ctx, "SET KEY_NAME VALUE_NAME");
redisReply *reply = (redisReply *)redisCommand(ctx, "SET %s %s", KEY_NAME, VALUE_DATA);
reply = (redisReply *)redisCommand(ctx, "GET %s", KEY_NAME);
All formats above may cause problems when you push and read. After lots of trials, I found the flawless format would be
redisReply *reply = (redisReply *)redisCommand(ctx, "RPUSH %s %s", KEY_NAME.c_str(), VALUE_DATA.c_str());
reply = (redisReply *)redisCommand(ctx, "GET %s", KEY_NAME.c_str());
you can also use KEY_NAME.data()
instead. The problem may be caused by the difference on string format for both Redis and c++. You have to use this format to push and read smoothly.
Redis Push and Read in Different Session
This problem is also caused by the string difference. If you push data in a key in the wrong format, the key’s name would be a messy code in redis if you type
(redis)127.0.0.1:6379> keys *
1) "`Y9\xbb\xff\x7f"
2) "\xe0\x9b\x8c\x81\xff\x7f"
3) ""
4) "\xf0\x97\x96\x99\xff\x7f"
5) "\xd0A\x0b\xfd\xfe\x7f"
6) " Y9\xbb\xff\x7f"
7) "\xc06&\xcf\xfd\x7f"
it shows clearly that you can’t recongnize any key’s name in redis. Consequently, you can’t get the right key’s name in another session and also can not get the right value.
Summary
- Reset MySQL needs to stop the service, reset in safe mode and restart service;
- The lost sock can be solved with soft link;
- Push and read data in Redis with CORRECT format;
- Reply pointer is the best way for debugging.