1、数据服务的逻辑循环
数据服务器的逻辑线程的循环里处理db玩家的存档数据
void main_logic_thread::run()
{
while(!isFinal())
{
setRunning();
main_logic_thread::currentTime.now();
g_server.handle_msg();//处理中心服务器消息
g_db_session_manager.handle_msg();
g_player_mgr.traverse_every_player(user_loop_exec);//遍历所有的玩家,处理缓存的数据,写到mysql数据库
...
}
...
}
struct EveryplayerLoopExec : public callback<db_player>
{
bool invoke(db_player *entry)
{
entry->loop();
#ifdef LY_DEBUG
//g_log->debug("角色在线:%u,%s",entry->id, entry->name.c_str());
#endif
return true;
}
}user_loop_exec;
bool db_player::loop()
{
checkFlush();//检查缓存,有数据就写到数据库
return true;
}
void db_player::checkFlush()
{
if (save_tag != 0)
{
save();
save_tag = 0;
}
}
2、处理接收的消息
把发来的角色数据存档消息写到缓存里
bool db_session::msgParse(const MSG::base_msg *ptrMsg, const unsigned int msglen)
{...
stWriteplayerRoleDataRecordCmd *rev = (stWriteplayerRoleDataRecordCmd*)ptrMsg;
db_player *pplayer = g_player_mgr.get_player_by_id(rev->charid);
if(pplayer)
{
pplayer->update_all(rev);//把发来的角色数据存档消息写到缓存里
}
...
}
角色存档的数据:角色属性数据、角色拓展数据
bool db_player::update_all(MSG::DB::stWriteplayerRoleDataRecordCmd *recv)
{
if(recv == NULL) return false;
update_roledata((const void*)&recv->data.roledata);
if(recv->data.size)
{
update_binary_buffer(&(recv->data.data[0]), recv->data.size);
}
//g_log->debug("%s,%u",__PRETTY_FUNCTION__, recv->data.size);
return true;
}
角色属性数据
bool db_player::update_roledata(const void* data)
{
bcopy(data, (void*)&(this->roledata), sizeof(RoleData));
this->save_tag |= (1<<SAVE_ROLE_DATA);//设置要存档的数据的标签
return true;
}
角色拓展数据:道具数据、任务数据、金钱数据、其他数据
bool db_player::update_binary_buffer(const char* pdata, const uint32 dataLen)
{
const char* data = pdata;
uint32 dataSize = 0;
while (dataSize != dataLen)
{
switch (*(uint32*)&data[dataSize])
{
case BinaryType_Item:
{
dataSize += sizeof(uint32);
uint32 itemSize = *(uint32*)(&data[dataSize]);
if(itemSize != 0)
{
bcopy((const void*)&data[dataSize], (void*)item_buffer, itemSize + sizeof(uint32));
dataSize += sizeof(uint32);
dataSize += itemSize;
save_tag |= (1<<SAVE_ITEM);
}
else
{
dataSize += sizeof(uint32);
}
//g_log->info("BinaryType_Item size:%u",itemSize);
}
break;
case BinaryType_Task:
{
dataSize += sizeof(uint32);
uint32 taskSize = *(uint32*)(&data[dataSize]);
if(taskSize != 0)
{
bcopy((const void*)&data[dataSize], (void*)task_buffer, taskSize + sizeof(uint32));
dataSize += sizeof(uint32);
dataSize += taskSize;
save_tag |= (1<<SAVE_TASK);
}
else
{
dataSize += sizeof(uint32);
}
//g_log->info("BinaryType_Task size:%u",taskSize);
}
break;
case BinaryType_Money:
{
dataSize += sizeof(uint32);
uint32 moneySize = *(uint32*)(&data[dataSize]);
if(moneySize != 0)
{
bcopy((const void*)&data[dataSize], (void*)money_buffer, moneySize + sizeof(uint32));
dataSize += sizeof(uint32);
dataSize += moneySize;
save_tag |= (1<<SAVE_MONEY);
}
else
{
dataSize += sizeof(uint32);
}
//g_log->info("BinaryType_Money size:%u",moneySize);
}
break;
case BinaryType_Other:
{
dataSize += sizeof(uint32);
uint32 otherSize = *(uint32*)(&data[dataSize]);
if(otherSize != 0)
{
bcopy((const void*)&data[dataSize], (void*)other_buffer, otherSize + sizeof(uint32));
dataSize += sizeof(uint32);
dataSize += otherSize;
save_tag |= (1<<SAVE_OTHER);
}
else
{
dataSize += sizeof(uint32);
}
//g_log->info("BinaryType_Other size:%u",otherSize);
}
break;
default:
{
g_log->error("角色[%u]二进制数据长度有误 %u,%u", this->id, dataLen, dataSize);
assert(0);
}
break;
}
}
return true;
}
3、把缓存数据写到数据库
bool db_player::save()
{
bool ret = false;
mysql_handle *handle = db_server::mysqlPool->getHandle();
if (!handle)
{
g_log->error("%u 不能从数据库连接池获取连接句柄", this->id);
return ret;
}
mysql_record column, where;
std::ostringstream os;
os << "charid = " << this->id;
where.put("charid", os.str());
if(save_tag & (1 << SAVE_ROLE_DATA))
{
column.put("pk", roledata.pk);
column.put("fight", roledata.fight);
column.put("mapid", roledata.mapid);
column.put("x", roledata.x);
column.put("y", roledata.y);
column.put("hp", roledata.hp);
column.put("mp", roledata.mp);
column.put("sp", roledata.sp);
column.put("sd",roledata.sd);
column.put("changeLife", (int16)roledata.changeLife);
column.put("changeJob",(int16)roledata.changeJob);
column.put("exp", roledata.exp);
column.put("nextexp", roledata.nextexp);
column.put("level", roledata.level);
column.put("leftAttrPoint", roledata.leftAttrPoint);
column.put("strength", roledata.strength);
column.put("agility", roledata.agility);
column.put("power", roledata.power);
column.put("intell", roledata.intell);
column.put("f_strength", roledata.f_strength);
column.put("f_agility", roledata.f_agility);
column.put("f_power", roledata.f_power);
column.put("f_intell", roledata.f_intell);
column.put("gold", roledata.gold);
column.put("silver", roledata.silver);
column.put("money", roledata.money);
column.put("bindmoney",roledata.bindmoney);
column.put("pkmode",(int16)roledata.pkmode);
column.put("psychicPower",roledata.psychicPower);
column.put("exchangedAttrNum",roledata.exchangedAttrNum);
column.put("levelstep",roledata.levelstep);
column.put("chaosVal",roledata.chaosVal);
column.put("pkstate",(int16)roledata.pkstate);
column.put("redType",(int16)roledata.redType);
column.put("bitmask", roledata.bitmask);
column.put("backdata", roledata.backdata);
column.put("onlinetime", roledata.onlinetime);
column.put("antiAddictionTime", roledata.antiAddictionTime);
column.put("firstLoginTime", roledata.firstLoginTime);
column.put("firstOfflineTime", roledata.firstOfflineTime);
column.put("lastLoginTime", roledata.lastLoginTime);
column.put("isOnline", roledata.isOnline);
column.put("lastOfflineTime", roledata.lastOfflineTime);
column.put("totalPayPoint", roledata.totalPayPoint);
column.put("activity",roledata.activity);
column.put("multiExpBeforeTwo",roledata.multiExpBeforeTwo);
column.put("multiExpBeforeOne",roledata.multiExpBeforeOne);
column.put("multiExpToday",roledata.multiExpToday);
column.put("attackMax",roledata.attackMax);
column.put("attackMagicMax",roledata.attackMagicMax);
column.put("attackSpeed",roledata.attackSpeed);
column.put("defend",roledata.defend);
column.put("autoUse",(int16)roledata.autoUse);
}
if(save_tag & (1<<SAVE_ITEM))
{
uint32 itemSize = *(uint32*)(&item_buffer);
column.put("itembinary", (const void *)(&item_buffer[4]), itemSize);
//g_log->debug("save itembinary size :%u", itemSize);
}
if(save_tag & (1<<SAVE_TASK))
{
uint32 taskSize = *(uint32*)(&task_buffer);
column.put("taskbinary", (const void *)(&task_buffer[4]), taskSize);
//g_log->debug("save taskbinary size :%u", taskSize);
}
if(save_tag & (1<<SAVE_MONEY))
{
uint32 moneySize = *(uint32*)(&money_buffer);
column.put("moneybinary", (const void *)(&money_buffer[4]), moneySize);
//g_log->debug("save moneybinary size :%u", moneySize);
}
if(save_tag & (1<<SAVE_OTHER))
{
uint32 otherSize = *(uint32*)(&other_buffer);
column.put("otherbinary", (const void *)(&other_buffer[4]), otherSize);
//g_log->debug("save otherbinary size :%u", otherSize);
}
uint32 affect = handle->exeUpdate("ROLE", &column, &where);
if (1 == affect || 0 == affect)
{
ret = true;
}
else
{
g_log->error("用户 [%u,%s] 存档失败,errno:%u,tag:%u", this->id,this->name.c_str(),affect,save_tag);
ret = false;
}
db_server::mysqlPool->putHandle(handle);
return ret;
}
4、执行mysql sql语句
(1)更新语句
把数据和条件组成sql语句来执行。
unsigned int mysql_handle::exeUpdate(const char *tablename, mysql_record* data, mysql_record* where)
{
mysql_table* table = this->pool->tm[this->_hashcode]->getTableByName(tablename);
if (NULL == data)
{
error_log("执行%s时data指针为空",__FUNCTION__);
return (unsigned int)-1;
}
if (NULL == _mysql)
{
error_log("执行%s时_mysql指针为空",__FUNCTION__);
return (unsigned int)-1;
}
if (NULL == table)
{
error_log("执行%s时table指针为空,找不到%s表",__FUNCTION__,tablename);
return (unsigned int)-1;
}
_update_time.now();
std::ostringstream query_string;
query_string << "UPDATE ";
query_string << "`" << table->name << "`";
query_string << " SET ";
struct UpdateExec : public callback<mysql_field>
{
bool _first;
mysql_table* _table;
std::ostringstream &query_string;
mysql_handle *_handle;
UpdateExec(mysql_table* table, std::ostringstream &query_string, mysql_handle *handle)
: _first(true), _table(table), query_string(query_string), _handle(handle)
{
}
bool invoke(mysql_field *entry)
{
mysql_field *basefield = _table->fs.get(entry->name.c_str());
if(!basefield)
{
return true;
}
if (_first)
{
_first=false;
}
else
{
query_string << " ,";
}
query_string << "`" << entry->name << "`" << " = ";
_handle->storeValue(_table, query_string, basefield->type, entry->data);
return true;
}
} udcb(table, query_string, this);
data->traverseField(udcb);
getWhere(table, query_string, where);
unsigned int ret = (unsigned int)-1;
if (0 == execSql(query_string.str().c_str(), query_string.str().size()))
{
ret = (unsigned int)mysql_affected_rows(_mysql);
}
if(_update_time.elapse(realtime()) >= 3 * 1000L)
{
std::ostringstream where_string;
getWhere(table, where_string, where);
g_log->warn("超时%llu毫秒sql:%s",_select_time.elapse(realtime()),query_string.str().c_str());
}
return ret;
}
数据服务器的逻辑线程的循环里处理db玩家的存档数据
void main_logic_thread::run()
{
while(!isFinal())
{
setRunning();
main_logic_thread::currentTime.now();
g_server.handle_msg();//处理中心服务器消息
g_db_session_manager.handle_msg();
g_player_mgr.traverse_every_player(user_loop_exec);//遍历所有的玩家,处理缓存的数据,写到mysql数据库
...
}
...
}