这一篇紧接着上一篇SequoiaDB 系列之六 :源码分析之coord节点来讲

在上一篇中,分析了coord转发数据包到catalog节点(也有可能是data节点,视情况而定)。这一次,我们继续分析上一篇中的rtnCoordCMDListCollectionSpace的消息包被转发到catalog节点上的处理流程。

catalog节点的进程,同样sequoiadb进程,只是角色不一样,运行的服务有区别。

这里就不再赘述catalog节点的启动过程。

在SequoiaDB/engine/cat/catalogueCB.cpp文件的最后,有代码:

sdbCatalogueCB* sdbGetCatalogueCB()
{
static sdbCatalogueCB s_catacb ;
return &s_catacb ;
}

当sdbGetCatalogueCB()第一次被调用的时候,会初始化sdbCatalogueCB的一个静态实例。
我们来看看sdbCatalogueCB类:

class sdbCatalogueCB : public _IControlBlock, public _IEventHander
{
public:
friend class catMainController ; typedef std::map<UINT32, string> GRP_ID_MAP;
typedef std::map<UINT16, UINT16> NODE_ID_MAP; public:
sdbCatalogueCB() ;
virtual ~sdbCatalogueCB() ; ... _netRouteAgent* netWork()
{
return _pNetWork;
}
catMainController* getMainController()
{
return &_catMainCtrl ;
}
catCatalogueManager* getCatlogueMgr()
{
return &_catlogueMgr ;
}
catNodeManager* getCatNodeMgr()
{
return &_catNodeMgr ;
}
catDCManager* getCatDCMgr()
{
return &_catDCMgr ;
}
catLevelLockMgr* getLevelLockMgr()
{
return &_levelLockMgr ;
} private:
_netRouteAgent *_pNetWork ;
_MsgRouteID _routeID ;
std::string _strHostName ;
std::string _strCatServiceName ;
NODE_ID_MAP _nodeIdMap ;
NODE_ID_MAP _sysNodeIdMap ;
GRP_ID_MAP _grpIdMap ;
GRP_ID_MAP _deactiveGrpIdMap ;
UINT16 _iCurNodeId ;
UINT16 _curSysNodeId ;
UINT32 _iCurGrpId ; catMainController _catMainCtrl ; // 这个是本次的重点
catCatalogueManager _catlogueMgr ;
catNodeManager _catNodeMgr ;
catDCManager _catDCMgr ;
catLevelLockMgr _levelLockMgr ;
} ;

在sdbCatalogueCB中,有一个成员变量,其类型是catMainController。
这个类是这样声明的:

class catMainController : public _pmdObjBase, public _netMsgHandler,
public _netTimeoutHandler
{
... public:
INT32 handleMsg( const NET_HANDLE &handle,
const _MsgHeader *header,
const CHAR *msg ) ;
void handleClose( const NET_HANDLE &handle, _MsgRouteID id ) ; void handleTimeout( const UINT32 &millisec, const UINT32 &id ) ; protected:
virtual INT32 _defaultMsgFunc ( NET_HANDLE handle,
MsgHeader* msg ) ; INT32 _processMsg( const NET_HANDLE &handle, MsgHeader *pMsg ) ; void _dispatchDelayedOperation( BOOLEAN dispatch ) ; protected:
INT32 _onActiveEvent( pmdEDUEvent *event ) ;
INT32 _onDeactiveEvent( pmdEDUEvent *event ) ; protected :
INT32 _processGetMoreMsg ( const NET_HANDLE &handle, MsgHeader *pMsg ) ;
INT32 _processQueryDataGrp( const NET_HANDLE &handle, MsgHeader *pMsg ) ;
INT32 _processQueryCollections( const NET_HANDLE &handle,
MsgHeader *pMsg ) ;
INT32 _processQueryCollectionSpaces ( const NET_HANDLE &handle,
MsgHeader *pMsg ) ;
INT32 _processQueryMsg( const NET_HANDLE &handle, MsgHeader *pMsg ) ;
INT32 _processKillContext(const NET_HANDLE &handle, MsgHeader *pMsg ) ;
INT32 _processAuthenticate( const NET_HANDLE &handle, MsgHeader *pMsg ) ;
INT32 _processAuthCrt( const NET_HANDLE &handle, MsgHeader *pMsg ) ;
INT32 _processAuthDel( const NET_HANDLE &handle, MsgHeader *pMsg ) ;
INT32 _processCheckRouteID( const NET_HANDLE &handle, MsgHeader *pMsg ) ;
INT32 _processInterruptMsg( const NET_HANDLE &handle,
MsgHeader *header ) ;
INT32 _processDisconnectMsg( const NET_HANDLE &handle,
MsgHeader *header ) ;
INT32 _processQueryRequest ( const NET_HANDLE &handle,
MsgHeader *pMsg,
const CHAR *pCollectionName ) ; protected:
INT32 _postMsg( const NET_HANDLE &handle, const MsgHeader *pHead ) ;
INT32 _catBuildMsgEvent ( const NET_HANDLE &handle,
const MsgHeader *pMsg,
pmdEDUEvent &event ) ;
INT32 _ensureMetadata() ;
INT32 _createSysIndex ( const CHAR *pCollection,
const CHAR *pIndex,
pmdEDUCB *cb ) ;
INT32 _createSysCollection ( const CHAR *pCollection,
pmdEDUCB *cb ) ;
void _addContext( const UINT32 &handle, UINT32 tid, INT64 contextID ) ;
void _delContextByHandle( const UINT32 &handle ) ;
void _delContext( const UINT32 &handle, UINT32 tid ) ;
void _delContextByID( INT64 contextID, BOOLEAN rtnDel ) ; ...
} ;

根据类的继承,可以猜想到这个类具备消息处理的能力。

这里,我们不深究到怎么收到网络消息的,我们只管怎么去处理网络消息的 :)

catMainController继承是_pmdObjBase的虚函数_defaultMsgFunc

INT32 catMainController::_defaultMsgFunc( NET_HANDLE handle,
MsgHeader * msg )
{
INT32 rc = SDB_OK ; _isDelayed = FALSE ;
_pCatCB->getCatDCMgr()->onCommandBegin( msg ) ; if ( MSG_CAT_CATALOGUE_BEGIN < (UINT32)msg->opCode &&
(UINT32)msg->opCode < MSG_CAT_CATALOGUE_END )
{
rc = _pCatCB->getCatlogueMgr()->processMsg( handle, msg ) ;
}
else if ( MSG_CAT_NODE_BEGIN < (UINT32)msg->opCode &&
(UINT32)msg->opCode < MSG_CAT_NODE_END )
{
rc = _pCatCB->getCatNodeMgr()->processMsg( handle, msg ) ;
}
else if ( MSG_CAT_DC_BEGIN < (UINT32)msg->opCode &&
(UINT32)msg->opCode < MSG_CAT_DC_END )
{
rc = _pCatCB->getCatDCMgr()->processMsg( handle, msg ) ;
}
else
{
rc = _processMsg( handle, msg ) ;
} _pCatCB->getCatDCMgr()->onCommandEnd( msg, rc ) ;
return rc ;
}

收到网络消息包后,交给对应的消息处理对象处理。而在coord节点上,交由rtnCoordCMDListCollectionSpace命令处理后的内部消息,消息类型是 MSG_CAT_CREATE_COLLECTION_SPACE_REQ,如此,这个消息会交给

rc = _pCatCB->getCatlogueMgr()->processMsg( handle, msg ) ; 

处理。跟进去

INT32 catCatalogueManager::processMsg( const NET_HANDLE &handle,
MsgHeader *pMsg )
{
INT32 rc = SDB_OK;
PD_TRACE_ENTRY ( SDB_CATALOGMGR_PROCESSMSG ) ;
PD_TRACE1 ( SDB_CATALOGMGR_PROCESSMSG,
PD_PACK_INT ( pMsg->opCode ) ) ; switch ( pMsg->opCode )
{
case MSG_CAT_CREATE_COLLECTION_REQ :
case MSG_CAT_DROP_COLLECTION_REQ :
case MSG_CAT_CREATE_COLLECTION_SPACE_REQ :
case MSG_CAT_DROP_SPACE_REQ :
case MSG_CAT_ALTER_COLLECTION_REQ :
case MSG_CAT_LINK_CL_REQ :
case MSG_CAT_UNLINK_CL_REQ :
case MSG_CAT_SPLIT_PREPARE_REQ :
case MSG_CAT_SPLIT_READY_REQ :
case MSG_CAT_SPLIT_CANCEL_REQ :
case MSG_CAT_SPLIT_START_REQ :
case MSG_CAT_SPLIT_CHGMETA_REQ :
case MSG_CAT_SPLIT_CLEANUP_REQ :
case MSG_CAT_SPLIT_FINISH_REQ :
case MSG_CAT_CRT_PROCEDURES_REQ :
case MSG_CAT_RM_PROCEDURES_REQ :
case MSG_CAT_CREATE_DOMAIN_REQ :
case MSG_CAT_DROP_DOMAIN_REQ :
case MSG_CAT_ALTER_DOMAIN_REQ :
{
_pCatCB->getCatDCMgr()->setImageCommand( TRUE ) ;
rc = processCommandMsg( handle, pMsg, TRUE ) ;
break;
}
case MSG_CAT_QUERY_SPACEINFO_REQ :
{
rc = processCommandMsg( handle, pMsg, TRUE ) ;
break;
}
case MSG_CAT_QUERY_CATALOG_REQ:
{
rc = processQueryCatalogue( handle, pMsg ) ;
break;
}
case MSG_CAT_QUERY_TASK_REQ:
{
rc = processQueryTask ( handle, pMsg ) ;
break ;
}
default:
{
rc = SDB_UNKNOWN_MESSAGE;
PD_LOG( PDWARNING, "received unknown message (opCode: [%d]%u)",
IS_REPLY_TYPE(pMsg->opCode),
GET_REQUEST_TYPE(pMsg->opCode) ) ;
break;
}
}
PD_TRACE_EXITRC ( SDB_CATALOGMGR_PROCESSMSG, rc ) ;
return rc;
}

该函数表明,大部分的消息(包括MSG_CAT_CREATE_COLLECTION_SPACE_REQ),都交由

processCommandMsg( handle, pMsg, TRUE )

处理去了。

显然,processCommandMsg是重点,我们看一下其具体实现:

INT32 catCatalogueManager::processCommandMsg( const NET_HANDLE &handle,
MsgHeader *pMsg,
BOOLEAN writable )
{
INT32 rc = SDB_OK ;
MsgOpQuery *pQueryReq = (MsgOpQuery *)pMsg ; PD_TRACE_ENTRY ( SDB_CATALOGMGR_PROCESSCOMMANDMSG ) ;
MsgOpReply replyHeader ;
rtnContextBuf ctxBuff ; INT32 opCode = pQueryReq->header.opCode ;
BOOLEAN fillPeerRouteID = FALSE ; INT32 flag = ;
CHAR *pCMDName = NULL ;
INT64 numToSkip = ;
INT64 numToReturn = ;
CHAR *pQuery = NULL ;
CHAR *pFieldSelector = NULL ;
CHAR *pOrderBy = NULL ;
CHAR *pHint = NULL ; replyHeader.header.messageLength = sizeof( MsgOpReply ) ;
replyHeader.contextID = - ;
replyHeader.flags = SDB_OK ;
replyHeader.numReturned = ;
replyHeader.startFrom = ;
_fillRspHeader( &(replyHeader.header), &(pQueryReq->header) ) ; if ( MSG_CAT_SPLIT_START_REQ == opCode ||
MSG_CAT_SPLIT_CHGMETA_REQ == opCode ||
MSG_CAT_SPLIT_CLEANUP_REQ == opCode ||
MSG_CAT_SPLIT_FINISH_REQ == opCode )
{
fillPeerRouteID = TRUE ;
} rc = msgExtractQuery( (CHAR*)pMsg, &flag, &pCMDName, &numToSkip,
&numToReturn, &pQuery, &pFieldSelector,
&pOrderBy, &pHint ) ;
PD_RC_CHECK( rc, PDERROR, "Failed to extract query msg, rc: %d", rc ) ; if ( writable && !pmdIsPrimary() )
{
rc = SDB_CLS_NOT_PRIMARY ;
PD_LOG ( PDWARNING, "Service deactive but received command: %s,"
"opCode: %d", pCMDName, pQueryReq->header.opCode ) ;
goto error ;
}
else if ( _pCatCB->getCatDCMgr()->isImageCommand() &&
!_pCatCB->isDCActive() )
{
rc = SDB_CAT_CLUSTER_NOT_ACTIVE ;
goto error ;
} switch ( pQueryReq->header.opCode )
{
case MSG_CAT_CREATE_COLLECTION_REQ :
rc = processCmdCreateCL( pQuery, ctxBuff ) ;
break ;
case MSG_CAT_CREATE_COLLECTION_SPACE_REQ :
rc = processCmdCreateCS( pQuery, ctxBuff ) ;
break ;
case MSG_CAT_SPLIT_PREPARE_REQ :
case MSG_CAT_SPLIT_READY_REQ :
case MSG_CAT_SPLIT_CANCEL_REQ :
case MSG_CAT_SPLIT_START_REQ :
case MSG_CAT_SPLIT_CHGMETA_REQ :
case MSG_CAT_SPLIT_CLEANUP_REQ :
case MSG_CAT_SPLIT_FINISH_REQ :
rc = processCmdSplit( pQuery, pQueryReq->header.opCode,
ctxBuff ) ;
break ;
case MSG_CAT_QUERY_SPACEINFO_REQ :
rc = processCmdQuerySpaceInfo( pQuery, ctxBuff ) ;
break ;
case MSG_CAT_DROP_COLLECTION_REQ :
rc = processCmdDropCollection( pQuery, pQueryReq->version ) ;
break ;
case MSG_CAT_DROP_SPACE_REQ :
rc = processCmdDropCollectionSpace( pQuery ) ;
break ;
case MSG_CAT_ALTER_COLLECTION_REQ :
rc = processAlterCollection( pQuery, ctxBuff ) ;
break ;
case MSG_CAT_CRT_PROCEDURES_REQ :
rc = processCmdCrtProcedures( pQuery ) ;
break ;
case MSG_CAT_RM_PROCEDURES_REQ :
rc = processCmdRmProcedures( pQuery ) ;
break ;
case MSG_CAT_LINK_CL_REQ :
rc = processCmdLinkCollection( pQuery, ctxBuff ) ;
break;
case MSG_CAT_UNLINK_CL_REQ :
rc = processCmdUnlinkCollection( pQuery, ctxBuff );
break;
case MSG_CAT_CREATE_DOMAIN_REQ :
rc = processCmdCreateDomain ( pQuery ) ;
break ;
case MSG_CAT_DROP_DOMAIN_REQ :
rc = processCmdDropDomain ( pQuery ) ;
break ;
case MSG_CAT_ALTER_DOMAIN_REQ :
rc = processCmdAlterDomain ( pQuery ) ;
break ;
default :
rc = SDB_INVALIDARG ;
PD_LOG( PDERROR, "Recieved unknow command: %s, opCode: %d",
pCMDName, pQueryReq->header.opCode ) ;
break ;
} PD_RC_CHECK( rc, PDERROR, "Process command[%s] failed, opCode: %d, "
"rc: %d", pCMDName, pQueryReq->header.opCode, rc ) ; done:
if ( fillPeerRouteID )
{
replyHeader.header.routeID.value = pQueryReq->header.routeID.value ;
} if ( == ctxBuff.size() )
{
rc = _pCatCB->netWork()->syncSend( handle, (void*)&replyHeader ) ;
}
else
{
replyHeader.header.messageLength += ctxBuff.size() ;
replyHeader.numReturned = ctxBuff.recordNum() ;
rc = _pCatCB->netWork()->syncSend( handle, &(replyHeader.header),
(void*)ctxBuff.data(),
ctxBuff.size() ) ;
}
PD_TRACE_EXITRC ( SDB_CATALOGMGR_PROCESSCOMMANDMSG, rc ) ;
return rc ;
error:
replyHeader.flags = rc ;
goto done ;
}

该函数先初始化了一个reply消息的头部,然后针对不同的消息,做对应的处理。例如我们例子中的 MSG_CAT_CREATE_COLLECTION_SPACE_REQ消息,交给 processCmdCreateCS 函数处理了;

PS:这个函数还分发了其它消息,如 创建Collection(createCollection)的消息,以及切分(split),删除Collection(dropCollection),删除CollectionSpace(dropCollectionSpace)等等操作,都会在catalog节点上有对应的处理(因为这类操作要修改元数据)。

回到处理MSG_CAT_CREATE_COLLECTION_SPACE_REQ上,processCmdCreateCS函数主要是传递了一下参数,具体的操作,交给了_createCS函数处理

INT32 catCatalogueManager::_createCS( BSONObj &createObj,
UINT32 &groupID )
{
INT32 rc = SDB_OK ;
string strGroupName ; const CHAR *csName = NULL ;
const CHAR *domainName = NULL ;
BOOLEAN isSpaceExist = FALSE ;
PD_TRACE_ENTRY ( SDB_CATALOGMGR__CREATECS ) ; catCSInfo csInfo ;
BSONObj spaceObj ;
BSONObj domainObj ;
vector< UINT32 > domainGroups ; rc = _checkCSObj( createObj, csInfo ) ;
PD_RC_CHECK( rc, PDERROR, "Check create collection space obj[%s] failed,"
"rc: %d", createObj.toString().c_str(), rc ) ;
csName = csInfo._pCSName ;
domainName = csInfo._domainName ; rc = dmsCheckCSName( csName ) ;
PD_RC_CHECK( rc, PDERROR, "Check collection space name[%s] failed, rc: "
"%d", csName, rc ) ; rc = catCheckSpaceExist( csName, isSpaceExist, spaceObj, _pEduCB ) ;
PD_RC_CHECK( rc, PDERROR, "Failed to check collection space existed, rc: "
"%d", rc ) ;
PD_TRACE1 ( SDB_CATALOGMGR_CREATECS, PD_PACK_INT ( isSpaceExist ) ) ;
PD_CHECK( FALSE == isSpaceExist, SDB_DMS_CS_EXIST, error, PDERROR,
"Collection space[%s] is already existed", csName ) ; if ( domainName )
{
rc = catGetDomainObj( domainName, domainObj, _pEduCB ) ;
PD_RC_CHECK( rc, PDERROR, "Failed to get domain[%s] obj, rc: %d",
domainName, rc ) ;
rc = catGetDomainGroups( domainObj, domainGroups ) ;
PD_RC_CHECK( rc, PDERROR, "Get domain[%s] groups failed, rc: %d",
domainObj.toString().c_str(), rc ) ;
} rc = _assignGroup( &domainGroups, groupID ) ;
PD_RC_CHECK( rc, PDERROR, "Assign group for collection space[%s] "
"failed, rc: %d", csName, rc ) ;
catGroupID2Name( groupID, strGroupName, _pEduCB ) ; {
BSONObjBuilder newBuilder ;
newBuilder.appendElements( csInfo.toBson() ) ;
BSONObjBuilder sub1( newBuilder.subarrayStart( CAT_COLLECTION ) ) ;
sub1.done() ; BSONObj newObj = newBuilder.obj() ; rc = rtnInsert( CAT_COLLECTION_SPACE_COLLECTION, newObj, , ,
_pEduCB, _pDmsCB, _pDpsCB, _majoritySize() ) ;
PD_RC_CHECK( rc, PDERROR, "Failed to insert collection space obj[%s] "
" to collection[%s], rc: %d", newObj.toString().c_str(),
CAT_COLLECTION_SPACE_COLLECTION, rc ) ;
} done:
PD_TRACE_EXITRC ( SDB_CATALOGMGR__CREATECS, rc ) ;
return rc ;
error:
goto done ;
}

这个函数会把网络消息的内容分解,然后对创建CollectionSpace的属性,选项做检查,检查通过之后,执行 rtnInsert 把一条记录插入 CAT_COLLECTION_SPACE_COLLECTION 所定义的系统表中;否则就返回检查出错时候的错误码,回复给corrd。具体插入过程,就不详细分析了。

PS:catalog也是一个数据库,具备多张系统元数据的表(Collection),表上存放整个数据库集群的元数据消息,例如集群有哪些节点,节点地址,节点的ID,每个集群有哪些CollectionSpace,有哪些Collection,以及整个数据库有哪些Domain,有哪些user等等。catalog描述是整个数据库集群的环境。

其它的命令,以后也不会一一分析了。结合上一篇分析,我们分析整个创建CollectionSpace的整个流程,从client调用创建接口,coord转发消息,到catalog收到消息,处理消息。

所有的命令或者操作,流程类似于此。涉及数据库元数据的,会先发送消息给catalog。对于CRUD消息,也会先请求catalog拿到准确的数据节点信息,然后再发送给对应的数据节点,由数据节点上执行。

总结一下SequoiaDB的客户端操作数据库的流程:

客户端发送请求给coord节点

coord先揪出这个请求是做什么

交给对应的command处理

查询(本地缓存或者远程获取的)catalog信息

把消息转成节点间的内部消息

转发给catalog目标节点

然后等待catalog处理返回数据

[

转发消息给数据节点

等待数据节点处理,返回数据

] // 绿色标识部分,如果不涉及到数据节点,可能不存在

再把返回数据交给处理线程

线程把返回结果发送给client

=====>THE END<=====

SequoiaDB 系列之七 :源码分析之catalog节点的更多相关文章

  1. 菜鸟系列Fabric源码学习 — committer记账节点

    Fabric 1.4 源码分析 committer记账节点 本文档主要介绍committer记账节点如何初始化的以及committer记账节点的功能及其实现. 1. 简介 记账节点负责验证交易和提交账 ...

  2. 死磕以太坊源码分析之p2p节点发现

    死磕以太坊源码分析之p2p节点发现 在阅读节点发现源码之前必须要理解kadmilia算法,可以参考:KAD算法详解. 节点发现概述 节点发现,使本地节点得知其他节点的信息,进而加入到p2p网络中. 以 ...

  3. SequoiaDB 系列之六 :源码分析之coord节点

    好久不见. 在上一篇SequoiaDB 系列之五   :源码分析之main函数,有讲述进程开始运行时,会根据自身的角色,来初始化不同的CB(控制块,control block). 在之前的一篇Sequ ...

  4. Spring基础系列-AOP源码分析

    原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/9560803.html 一.概述 Spring的两大特性:IOC和AOP. AOP是面向切 ...

  5. Flask系列之源码分析(一)

    目录: 涉及知识点 Flask框架原理 简单示例 路由系统原理源码分析 请求流程简单源码分析 响应流程简单源码分析 session简单源码分析 涉及知识点 1.装饰器 闭包思想 def wapper( ...

  6. Tomcat详解系列(3) - 源码分析准备和分析入口

    Tomcat - 源码分析准备和分析入口 上文我们介绍了Tomcat的架构设计,接下来我们便可以下载源码以及寻找源码入口了.@pdai 源代码下载和编译 首先是去官网下载Tomcat的源代码和二进制安 ...

  7. Hadoop源码分析之数据节点的握手,注册,上报数据块和心跳

    转自:http://www.it165.net/admin/html/201402/2382.html 在上一篇文章Hadoop源码分析之DataNode的启动与停止中分析了DataNode节点的启动 ...

  8. Kafka源码系列之源码分析zookeeper在kafka的作用

    浪尖的kafka源码系列以kafka0.8.2.2源码为例给大家进行讲解的.纯属个人爱好,希望大家对不足之处批评指正. 一,zookeeper在分布式集群的作用 1,数据发布与订阅(配置中心) 发布与 ...

  9. Android进阶系列之源码分析Activity的启动流程

    美女镇楼,辟邪! 源码,是一个程序猿前进路上一个大的而又不得不去翻越障碍,我讨厌源码,看着一大堆.5000多行,要看完得啥时候去了啊.不过做安卓的总有这一天,自从踏上这条不归路,我就认命了.好吧,我慢 ...

随机推荐

  1. Windows 系统下json 格式的日志文件发送到elasticsearch

    Windows 系统下json 格式的日志文件发送到elasticsearch配置 Nxlog-->logstash-->ElasticSearch Logstash https://ww ...

  2. CEPH块设备创建及快照

    1.创建image rbd create foo --size 1024 {--image-format 2}//创建一个名为foo的image,大小为1024M,当需要克隆快照时,需要添加大括号中的 ...

  3. select2取值报错,Failed to read the 'selectionDirection' property from 'HTMLInputElement': The input element's type ('hidden') does not support selection.

    用到了 select2 组件来多选收件人,用搜狗浏览器(6.2版高速模式)在执行到如下这句时报错(Uncaught InvalidStateError: Failed to read the 'sel ...

  4. win8程序开机自启动管理

    主要介绍利用系统自身的工具来管理开机自启动,而非第三方的工具,自己了解了,也写出来分享给大家@.·.@ 1.程序设置开机自启动 a. 打开计算机资源管理器-->进入"C:\Progra ...

  5. 利用jquery来进行表单的多向提交

    最近由于特别忙,每晚都是1到2点倒床便睡的那种,所以没有给自己要求写日记,等这阶段过完,还会重新开始. 今天来写一个前端的表单提交的方法. 有时往往以为在同一个表单中,不同的按钮,来表达的含义不同,需 ...

  6. 权限框架 - shiro 自定义realm

    上篇文章中是使用的默认realm来实现的简单登录,这仅仅只是个demo,真正项目中使用肯定是需要连接数据库的 首先创建自定义realm文件,如下: 在shiro中注入自定义realm的完全限定类名: ...

  7. JAVA NIO概述(一):I/O模型

    NIO是jdk1.4加入的新功能,我们一般成为非阻塞IO,在1.4之前,JAVA中的都是BIO(堵塞IO),BIO有以下几个缺点: 没有数据缓冲区,I/O性能存在问题 没有C/C++中channel( ...

  8. java 21 - 15 新IO流 NIO

    1:JDK4  新IO要了解的类 Buffer(缓冲),Channer(通道) 2:JDK7  要了解的新IO类 Path:与平台无关的路径. Paths:包含了返回Path的静态方法. public ...

  9. Linux下利用CGroup控制CPU、内存以及IO的操作记录

    CGroup及其子系统的介绍在这里就不赘述了,可以参考:Linux下CGroup使用说明梳理废话不多说,这里记录下利用CGroup控制CPU.内存以及IO的操作记录: libcgroup工具安装这里以 ...

  10. templatecolumn checkcolumn