本博客与RayXXZhang的博客保持同步更新,转载请注明来自RayXXZhang的博客-nsq源码阅读笔记之nsqd(三)——diskQueue
diskQueue
是backendQueue
接口的一个实现。backendQueue
的作用是在实现在内存go channel缓冲区满的情况下对消息的处理的对象。
除了diskQueue
外还有dummyBackendQueue
实现了backendQueue
接口。
对于临时(#ephemeral结尾)Topic/Channel,在创建时会使用dummyBackendQueue
初始化backend
,
dummyBackendQueue
只是为了统一临时和非临时Topic/Channel而写的,它只是实现了接口,不做任何实质上的操作,
因此在内存缓冲区满时直接丢弃消息。这也是临时Topic/Channel和非临时的一个比较大的差别。
每个非临时Topic/Channel,创建的时候使用diskQueue
初始化backend
,diskQueue
的功能是将消息写入磁盘进行持久化,
并在需要时从中取出消息重新向客户端投递。
diskQueue
的实现在nsqd/disk_queue.go
中。需要注意一点,查找diskQueue
中的函数的调用可能不会返回正确的结果,
因为diskQueue
对外是以backendQueue
形式存在,因此查找diskQueue
的函数的调用情况时应当查找backendQueue
中相应函数的调用。
diskQueue
的创建和初始化
// newDiskQueue instantiates a new instance of diskQueue, retrieving metadata
// from the filesystem and starting the read ahead goroutine
func newDiskQueue(name string, dataPath string, maxBytesPerFile int64,
minMsgSize int32, maxMsgSize int32,
syncEvery int64, syncTimeout time.Duration,
logger logger) BackendQueue {
d := diskQueue{
name: name,
dataPath: dataPath,
maxBytesPerFile: maxBytesPerFile,
minMsgSize: minMsgSize,
maxMsgSize: maxMsgSize,
readChan: make(chan []byte),
writeChan: make(chan []byte),
writeResponseChan: make(chan error),
emptyChan: make(chan int),
emptyResponseChan: make(chan error),
exitChan: make(chan int),
exitSyncChan: make(chan int),
syncEvery: syncEvery,
syncTimeout: syncTimeout,
logger: logger,
}
// no need to lock here, nothing else could possibly be touching this instance
err := d.retrieveMetaData()
if err != nil && !os.IsNotExist(err) {
d.logf("ERROR: diskqueue(%s) failed to retrieveMetaData - %s", d.name, err)
}
go d.ioLoop()
return &d
}
diskQueue
的获得是通过newDiskQueue
,该函数比较简单,通过传入的参数创建一个dispQueue
,
然后通过retrieveMetaData
函数获取之前与该diskQueue
相关联的Topic/Channel已经持久化的信息。最后启动ioLoop
循环处理消息。
// retrieveMetaData initializes state from the filesystem
func (d *diskQueue) retrieveMetaData() error {
var f *os.File
var err error
fileName := d.metaDataFileName()
f, err = os.OpenFile(fileName, os.O_RDONLY, 0600)
if err != nil {
return err
}
defer f.Close()
var depth int64
_, err = fmt.Fscanf(f, "%d\n%d,%d\n%d,%d\n",
&depth,
&d.readFileNum, &d.readPos,
&d.writeFileNum, &d.writePos)
if err != nil {
return err
}
atomic.StoreInt64(&d.depth, depth)
d.nextReadFileNum = d.readFileNum
d.nextReadPos = d.readPos