func (scan *HeapScan) getBuffer(blockNum system.BlockNumber) (storage.Buffer, system.BlockNumber, error) { // release previous scan buffer, if any if scan.cBuf.IsValid() { scan.bufMgr.ReleaseBuffer(scan.cBuf) scan.cBuf = storage.InvalidBuffer() } // read page buf, err := scan.bufMgr.ReadBuffer(scan.rel.RelNode, blockNum) if err != nil { return storage.InvalidBuffer(), system.InvalidBlockNumber, err } return buf, blockNum, nil }
func (scan *HeapScan) Next() (Tuple, error) { var lineOff system.OffsetNumber var cBlock system.BlockNumber = system.InvalidBlockNumber tuple := scan.cTuple if !scan.inited { // return immediately if relation is empty if scan.nBlocks == 0 { tuple.SetData(nil, system.InvalidItemPointer) return nil, nil } cBlock = scan.startBlock if buf, block, err := scan.getBuffer(cBlock); err != nil { return nil, err } else { scan.cBuf, scan.cBlock = buf, block } lineOff = system.FirstOffsetNumber scan.inited = true } else { // continue from previously returned page/tuple cBlock = scan.cBlock lineOff = tuple.self.OffsetNumber().Next() } scan.cBuf.RLock() page := scan.cBuf.GetPage() nLines := page.MaxOffsetNumber() linesLeft := nLines - lineOff + 1 itemId := page.ItemId(lineOff) for { for linesLeft > 0 { if itemId.IsNormal() { tid := system.MakeItemPointer(cBlock, lineOff) tuple.SetData(page.Item(itemId), tid) // TODO: valid = HeapTupleSatisfyiesVisibility() scan.cBuf.Unlock() } // otherwise move to the next item on the page linesLeft-- lineOff++ itemId = page.ItemId(lineOff) } // if we get here, it means we've exhausted the items on this page and // it's time to move to the next. scan.cBuf.Unlock() cBlock++ if cBlock >= scan.nBlocks { cBlock = 0 } finished := cBlock == scan.startBlock if finished { if scan.cBuf.IsValid() { scan.bufMgr.ReleaseBuffer(scan.cBuf) } scan.cBuf = storage.InvalidBuffer() scan.cBlock = system.InvalidBlockNumber tuple.SetData(nil, system.InvalidItemPointer) scan.inited = false return nil, nil } if buf, block, err := scan.getBuffer(cBlock); err != nil { return nil, err } else { scan.cBuf, scan.cBlock = buf, block } scan.cBuf.RLock() page = scan.cBuf.GetPage() nLines = page.MaxOffsetNumber() linesLeft = nLines lineOff = system.FirstOffsetNumber itemId = page.ItemId(lineOff) } }