为我新的一天没有放弃而喝彩

  1. 为我新的一天没有放弃而喝彩
  
  学习是一件很容易放弃的事情,因为就算是不学,我也能在现在的岗位上发光发热。可是人不就是一个热爱折腾的种群吗?
  
  今天没有放弃不代表明天没有放弃,也许放弃的可能性大于坚持的可能性,不管怎样,坚持一天算一天。
  
  RadonDB面对着TiDB,OceanBase等等数据库的竞争,都是分布式数据库,为什么要首先学习RadonDB呢?毕竟这是一款真的基于MySQL而不是兼容MySQL的产品,通过学习RadonDB,也许有一天我能在其源码上做出点什么贡献也未可知,我起码对MySQL的熟悉程度更高。
  
  2. 继续昨天的话题
  
  昨天我写到了程序的主入口,注意其最重要的一句:
  
  // Proxy.
  
  proxy := proxy.NewProxy(log, flagConf, build.Tag, conf)
  
  proxy.Start()
  
  一切都是从这里开始的,为什么这么说呢?
  
  这一启动,就好像启动了一个mysqld一样,可以正常的接收mysql客户端的连接请求。
  
  根据昨天讲述的,proxy的启动实际上是执行了Accept方法,而Accept则是以服务形式启动起来,并且监听了几个端口的。
  
  那我们再来看看Accept方法:
  
  // Accept runs an accept loop until the listener is closed.
  
  func (l *Listener) Accept(www.hongchenyul.cn) {
  
  runtime.GOMAXPROCS(runtime.NumCPU())
  
  for {
  
  conn, err := l.listener.Accept()
  
  if err != nil {
  
  // Close() was probably called.
  
  return
  
  }
  
  ID := l.connectionID
  
  l.connectionID++
  
  go l.handle(conn, ID, l.serverVersion)
  
  }
  
  }
  
  从代码逻辑上看,只要没有执行Close,就会一直循环监听下去,监听的就是一个一个的网络连接请求。
  
  我猜测这里的连接就好像是我们在MySQL中执行“show processlist”的时候,显示的信息,每来一个连接,就会给它分配一个ID,并启动一个监听器的handler goroutine,可以理解为启动了一个线程,这个线程专门负责该连接。
  
  到这里我们就可以肯定,RadonDB也是一个单进程多线程的架构,和MySQL并无二致。
  
  现在就可以分析分析handler方法到底做了什么。这个方法很长很长,我实在是不能一行一行的粘贴过来,只是捡一些有代表性的讲讲。
  
  // handle is called in a go routine for each client connection.
  
  func (l *Listener) handle(conn net.Conn, ID uint32, serverVersion string) {}
  
  首先映入眼帘的一定是注释,良好的代码一定拥有良好的注释。注释告诉我们,这个handler方法是处理每个客户端连接的。
  
  客户端连接嘛,每个DBA都知道,连接上来就是为了执行SQL的命令的,有一般的DDL,DML还有些指令性命令。
  
  那么我推断代码里一定有一个switch分支用于对每种命令进行处理:
  
  for {
  
  if data, err = session.packets.Next(www.baichuangyule.cn); err != nil {
  
  return
  
  }
  
  // Update the session last query time for session idle.
  
  session.updateLastQueryTime(time.Now())
  
  switch data[0] {
  
  // COM_QUIT
  
  case sqldb.COM_QUIT:
  
  return
  
  // COM_INIT_DB
  
  case sqldb.COM_INIT_DB:
  
  db := l.parserComInitDB(data)
  
  if err = l.handler.ComInitDB(session,www.mxdpt.cn db); err != nil {
  
  if werr := session.writeErrFromError(err); werr != nil {
  
  return
  
  }
  
  } else {
  
  session.SetSchema(db)
  
  if err = session.packets.WriteOK(0, 0, session.greeting.Status(), 0); err != nil {
  
  return
  
  }
  
  }
  
  // COM_PING
  
  case sqldb.COM_PING:
  
  if err = session.packets.WriteOK(0, www.cmyuLept.com  , session.greeting.Status(), 0); err != nil {
  
  return
  
  }
  
  // COM_QUERY
  
  case sqldb.COM_QUERY:
  
  query := l.parserComQuery(data)
  
  if err = l.handler.ComQuery(session, query, nil, func(qr *sqltypes.Result) error {
  
  return session.writeTextRows(qr)
  
  }); err != nil www.shengrenpt1.cn {
  
  log.Error("server.handle.query.from.session[%v].error:%+v.query[%s]", ID, err, query)
  
  if werr := session.writeErrFromError(err); werr != nil {
  
  return
  
  }
  
  }
  
  //省略其他
  
  还真的是有,逻辑也不复杂,其实刚才的代码里没有展现出session的概念,先讲讲session在回过头来讲刚才的代码:
  
  session := newSession(log, ID, l.serverVersion, conn)
  
  //省略一些session的检查等操作
  
  l.handler.SessionInc(session)
  
  defer l.handler.SessionDec(session)
  
  // Reset packet sequence ID.
  
  session.packets.ResetSeq()
  
  核心思想就是新建了一个session,之后,才有了刚才的操作,要从session中拿出用户操作来,放在一个叫做data的切片中,然后判断切片中具体的操作类型。
  
  到这里应该很多人都会知道,RadonDB到底做了一个什么样的入口了,其实就是做了一个自己的MySQL服务,监听特定的端口,接收用户的操作。
  
  这里所有的代码都可以参考以下这个github项目:
  
  go-mysqlstack
  
  作者也是RadonDB的作者之一。这个go-mysqlstack的目的也很简单,就是实现一个mysqld:
  
  官方给的示例,就是启动了一个服务端:
  
  对于交付的客户来说,其实就是在用MySQL,只不过端口有变,服务的启动方式和配置方式不太一样,但是写代码还是用jdbc-driver,对于开发者来说没有任何变化。
  
  3. 小结
  
  Go语言真有意思,利用已经成熟的项目来学习Go语言,我觉得比一点一点看书来的快一些。
  
  当然了,学会了写之后就要思考,思考这门语言,真的做到Thinking in Go。
  
  真是学而不思则罔。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值