nsq源码分析(3):nsqd之数据持久化2
来源:互联网 发布:粒子群算法的gui 编辑:程序博客网 时间:2024/05/17 03:47
nsq源码分析(3):nsqd之数据持久化2
当nsqd进程退出时,将内存中的数据写入到磁盘
当nsqd进程启动时,将磁盘中的数据读入到内存
nsqd数据信息结构体
nsqd/nsqd.go
type meta struct { Topics []struct { Name string `json:"name"` // topic名称 Paused bool `json:"paused"` // topic状态 Channels []struct { Name string `json:"name"` // channel名称 Paused bool `json:"paused"` // channel状态 } `json:"channels"` } `json:"topics"`}
nsqd退出时写入本地元数据
nsqd/nsqd.go
func (n *NSQD) Exit() { ... n.Lock() err := n.PersistMetadata() if err != nil { n.logf("ERROR: failed to persist metadata - %s", err) } n.logf("NSQ: closing topics") for _, topic := range n.topicMap { topic.Close() } n.Unlock() ...}
nsqd/nsqd.go
// 将topic和channel的信息写入磁盘func (n *NSQD) PersistMetadata() error { // persist metadata about what topics/channels we have, across restarts // fileName:nsqd数据文件名。保存topic和channels的相关信息 // 根据用户传参data-path指定数据目录,文件命名为nsqd.dat fileName := newMetadataFile(n.getOpts()) // old metadata filename with ID, maintained in parallel to enable roll-back // fileNameID:id json数据文件名称。 // fileNameID文件是fileName文件的软连接,内容和fileName一样,用于回滚操作。文件命名为nsqd.867.dat // nsqd.867.dat这里的867是opts.ID,根据主机名的哈希值算出的0-1024之间的值 fileNameID := oldMetadataFile(n.getOpts()) n.logf("NSQ: persisting topic/channel metadata to %s", fileName) // 遍历所有的topic和channel。注:在调用PersistMetadata之前就加上了lock锁 // 拿到所有topic和channel的name和paused字段,paused描述该topic或channel的状态 js := make(map[string]interface{}) topics := []interface{}{} for _, topic := range n.topicMap { if topic.ephemeral { continue } topicData := make(map[string]interface{}) topicData["name"] = topic.name topicData["paused"] = topic.IsPaused() channels := []interface{}{} topic.Lock() for _, channel := range topic.channelMap { channel.Lock() if channel.ephemeral { channel.Unlock() continue } channelData := make(map[string]interface{}) channelData["name"] = channel.name channelData["paused"] = channel.IsPaused() channels = append(channels, channelData) channel.Unlock() } topic.Unlock() topicData["channels"] = channels topics = append(topics, topicData) } js["version"] = version.Binary js["topics"] = topics // 序列化成json字符串 data, err := json.Marshal(&js) if err != nil { return err } // 写入nsqd数据文件(nsqd.dat) tmpFileName := fmt.Sprintf("%s.%d.tmp", fileName, rand.Int()) err = writeSyncFile(tmpFileName, data) if err != nil { return err } err = os.Rename(tmpFileName, fileName) if err != nil { return err } // technically should fsync DataPath here stat, err := os.Lstat(fileNameID) if err == nil && stat.Mode()&os.ModeSymlink != 0 { return nil } // if no symlink (yet), race condition: // crash right here may cause next startup to see metadata conflict and abort // 创建nsqd数据文件的软连接(nsqd.867.dat) tmpFileNameID := fmt.Sprintf("%s.%d.tmp", fileNameID, rand.Int()) if runtime.GOOS != "windows" { err = os.Symlink(fileName, tmpFileNameID) } else { // on Windows need Administrator privs to Symlink // instead write copy every time err = writeSyncFile(tmpFileNameID, data) } if err != nil { return err } err = os.Rename(tmpFileNameID, fileNameID) if err != nil { return err } // technically should fsync DataPath here return nil}
nsqd启动时加载本地元数据
apps/nsqd/nsqd.go
func (p *program) Start() error { ... // 加载元数据 err := nsqd.LoadMetadata() if err != nil { log.Fatalf("ERROR: %s", err.Error()) } ...}
nsqd/nsqd.go
// 加载磁盘中的topic和channel信息func (n *NSQD) LoadMetadata() error { atomic.StoreInt32(&n.isLoading, 1) defer atomic.StoreInt32(&n.isLoading, 0) fn := newMetadataFile(n.getOpts()) // old metadata filename with ID, maintained in parallel to enable roll-back fnID := oldMetadataFile(n.getOpts()) // 读取nsqd数据文件和nsqd数据文件的软连接文件(用于回滚操作) data, err := readOrEmpty(fn) if err != nil { return err } dataID, errID := readOrEmpty(fnID) if errID != nil { return errID } if data == nil && dataID == nil { return nil // fresh start } if data != nil && dataID != nil { if bytes.Compare(data, dataID) != 0 { return fmt.Errorf("metadata in %s and %s do not match (delete one)", fn, fnID) } } if data == nil { // only old metadata file exists, use it fn = fnID data = dataID } var m meta err = json.Unmarshal(data, &m) if err != nil { return fmt.Errorf("failed to parse metadata in %s - %s", fn, err) } // 将nsqd数据文件的json反序列化到Topic和Channels for _, t := range m.Topics { if !protocol.IsValidTopicName(t.Name) { n.logf("WARNING: skipping creation of invalid topic %s", t.Name) continue } topic := n.GetTopic(t.Name) if t.Paused { topic.Pause() } for _, c := range t.Channels { if !protocol.IsValidChannelName(c.Name) { n.logf("WARNING: skipping creation of invalid channel %s", c.Name) continue } channel := topic.GetChannel(c.Name) if c.Paused { channel.Pause() } } } return nil}
阅读全文
0 0
- nsq源码分析(3):nsqd之数据持久化
- nsq源码分析(3):nsqd之数据持久化2
- NSQ源码剖析之nsqd
- nsq源码阅读笔记之nsqd(一)——nsqd的配置解析和初始化
- nsq源码阅读 nsqd源码一 apps/nsqd/nsqd.go
- nsq源码阅读 nsqd源码二 nsqd/nsqd.go
- nsq源码阅读笔记之nsqd(二)——Topic
- nsq源码阅读笔记之nsqd(三)——diskQueue
- nsq源码阅读笔记之nsqd(四)——Channel
- nsq源码分析(2):nsqlookup之启动和停止
- nsq源码分析(2):nsqlookup之http服务
- nsq源码分析(2):nsqlookup之tcp服务
- nsq源码分析(2):nsqlookup之RegistrationDB数据库
- nsq源码导读(1.1) nsq的核心nsqd
- NSQ源码分析之概述
- NSQ源码分析之nsqlookupd
- nsq源码阅读 nsqd源码三 tcp.go
- nsq源码分析(1):代码结构
- 中科爱讯WiFi探针在客流分析统计的应用
- maxscript通过DOTNET创建MAX风格的窗体
- WPF三维图形
- ng-repeat报错
- SLF4J和log4j的使用
- nsq源码分析(3):nsqd之数据持久化2
- Expression Blend学习动画基础
- js监控回车的案例
- ckfinder 低版本无法排序 2.6.2.1可以
- switch多个case执行一段代码
- HDU 1250 Hat's Fibonacci()
- 微信公众号一次二次转发链接地址是IP和图片不显示,转换成文字和图片分享到朋友圈问题
- CEO无限期休假 Uber或踏上企业文化重建之路
- springmybaits org.mybatis.spring.transaction.SpringManagedTransaction.getTimeout()Ljava/lang/Integer