Chinaunix首页 | 论坛 | 博客
  • 博客访问: 202866
  • 博文数量: 11
  • 博客积分: 4010
  • 博客等级: 上校
  • 技术积分: 160
  • 用 户 组: 普通用户
  • 注册时间: 2006-07-03 14:24
个人简介

从客服技术支持到程序开发 从传统电信行业到互联网,以及移动互联网 岁月流逝,梦想依旧 个人订阅号--licaduo

文章分类

全部博文(11)

文章存档

2010年(11)

我的朋友

分类: C/C++

2010-06-15 01:34:38

引言:
    我们的项目是做即时语音聊天,服务器需要保持用户在线信息。在语音包来了之后需要立刻查询目标用户地址,然后发送出去。假设用户说话的时候一秒钟发送6个语音包。那么针对这一个用户就需要在一秒内查询6次数据库。想象当服务器内有1000个用户同时说话的时候,这个查询量就会很大。
    针对这种类似的程序启动才会产生数据,程序退出清空数据,需要快速查询的应用,把这个需要查询的数据放入数据库中就有些不太合适。数据库中的数据查询分3个步骤实现:首先,通过tcp把查询请求发到数据库服务器;接下来,数据库服务器查询相应数据,之后,数据库服务器把查询结果通过tcp发还给应用程序。通过数据库查询数据,即使查询数据过程再短,也还是需要经过两次网络传输。为了提高查询速度,相应的解决方法是把数据放入应用程序的进程空间的内存中。由应用程序自己实现一个类似 数据库表管理的一个功能,相应的针对具体的查询条件实现简单的索引。暂且把这种放在自己进程空间内存中的数据库表叫 内存表----或许这个称谓不官方,也不科学。
    下面结合具体的代码实现一个简单的内存表。
 
    首先定义一个表结构,
struct T_Table
{
 int  nId;     //主键
 int  nItem1;
 int  nItem2;
 string  sName;
 
};
    
    接下来确定查询条件。假设需要针对 nId,sName,做两个索引。其中nId是唯一索引,sName不是唯一索引。
    根据上面的需求,我们需要实现下面这样一个类:

class CTable
{
public:
 //构造函数
 CTable();
 //析构函数
 ~CTable();
 //以id为索引的查询
 T_Table* m_GetById(int nId);
 //以name为索引的查询
 vector m_GetByName(string sName);
 //插入数据
 void m_Insert(int nId,int  nItem1,int  nItem2,string  sName);
 //删除数据
 void m_Delete(int nId);
 //根据id进行数据更新呢
 void m_UpdateById(int nId,int nItem1);
 //根据name进行数据更新
 void m_UpdateByName(string nName,int nItem1);
protected:
private:
 //以id为索引的数据存储
 map  m_IndexDataById;
 //以name为索引的数据存储
 multimap  m_IndexDataByName;
 //读写锁
 pthread_rwlock_t            m_Lock;
};    
    下面给出一个简单的实现代码
CTable::CTable()
{
 //初始化锁
 pthread_rwlock_init(&m_Lock,NULL);
}
CTable::~CTable()
{
 pthread_rwlock_wrlock(&m_Lock);
 //释放数据内存
 for (map::iterator it = m_IndexDataById.begin();it!= m_IndexDataById.end();it++)
 {
  delete it->second;
  it->second = NULL;
 }
 //清空索引数据
 m_IndexDataById.clear();
 m_IndexDataByName.clear();
 pthread_rwlock_unlock(&m_Lock);
 //释放锁资源
 pthread_rwlock_destroy(&m_Lock);  
}
T_Table* CTable::m_GetById(int nId)
{
 pthread_rwlock_rdlock(&m_Lock);
 map::iterator it = m_IndexDataById.find(nId);
 if (it != m_IndexDataById.end())
 {
  pthread_rwlock_unlock(&m_Lock);
  return it->second;
 }
 else
 {
  pthread_rwlock_unlock(&m_Lock);
  return NULL;
 }
}
vector CTable::m_GetByName(string sName)
{
  vector  vData;
 pthread_rwlock_rdlock(&m_Lock);
 for (multimap::iterator it = m_IndexDataByName.lower_bound(nName);
  it != m_IndexDataByName.upper_bound(nName);it++)
 {
vData.push_back(it->second);
  }  
pthread_rwlock_unlock(&m_Lock);
  return vData;
 
}
void CTable::m_Insert(int nId,int  nItem1,int  nItem2,string  sName)
{
 T_Table* pData = new T_Table;
 memset(pData,0,sizeof(T_Table));
 pData->nId = nId;
 pData->nItem1 = nItem1;
 pData->nItem2 = nItem2;
 pData->sName = sName;
 pthread_rwlock_wrlock(&m_Lock); 
 m_IndexDataById[nId] = pData;
 m_IndexDataByName[sName] = pData;
 pthread_rwlock_unlock(&m_Lock);
}
void CTable::m_Delete(int nId)
{
 pthread_rwlock_wrlock(&m_Lock); 
 map::iterator it = m_IndexDataById.find(nId);
 m_IndexDataByName.erase(m_IndexDataByName.find(it->second->sName));
 m_IndexDataById.erase(it);
 pthread_rwlock_unlock(&m_Lock);
}
void CTable::m_UpdateById(int nId,int nItem1)
{
 pthread_rwlock_wrlock(&m_Lock); 
 (m_IndexDataById.find(nId)->second)->nItem1 = nItem1;
 pthread_rwlock_unlock(&m_Lock);
}
void CTable::m_UpdateByName(string nName,int nItem1)
{
 pthread_rwlock_wrlock(&m_Lock); 
 for (multimap::iterator it = m_IndexDataByName.lower_bound(nName);
  it != m_IndexDataByName.upper_bound(nName);it++)
 {
  it->second->nItem1 = nItem1;
 }
 pthread_rwlock_unlock(&m_Lock);
}
 
     如果需要增加新的唯一索引,就增加一个map数据存储,map的key就是索引列,value就是对应的数据行。相应的如果需要增加一个非唯一索引,就增加一个multimap的数据结构。在增加了索引之后相应的要增加索引相对的查询,更新函数。这里采用map去存储数据应该能够满足表大小5000行以下的数据查询需求。如果数据行数超过5000行,可以考虑采用hashmap存储数据。同时考虑采用多个读写锁,一个读写锁管理一部分数据。
     这只是我在应用中想到的一个解决方法,如果有更好的解决方法,希望多多指正。
 
 
 
 
 
阅读(2902) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~