[linux] page 写磁盘并不是原子性
Posted adream307
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[linux] page 写磁盘并不是原子性相关的知识,希望对你有一定的参考价值。
以 page
为单位,向磁盘写数据,并不是原子性的,举例说明:
- 写线程
writer
每次向磁盘输入一个page
的数据量,w1 w2 w3 ...
w1 w2 w3 ...
分别代表一个page
的数据量- 读线程
reader
每次从磁盘读一个page
的数据量 - 操作系统并不保证
writer
写完整个page
后,才让当前写入的数据整体对reader
可见 reader
读取一个pape
的数据,可能部分来自w1
部分来自w2
测试代码如下:
package main
import (
"fmt"
"hash/fnv"
"log"
"math/rand"
"os"
"sync"
"syscall"
"unsafe"
)
func randPage(page []byte)
size := int(unsafe.Sizeof(uint64(0)))
uintLen := len(page) / size
for i := 0; i < uintLen-1; i++
dPtr := (*uint64)(unsafe.Pointer(&page[i*size]))
*dPtr = rand.Uint64()
func hashPage(page []byte) uint64
hashEnd := len(page) - int(unsafe.Sizeof(uint64(0)))
h := fnv.New64a()
_, _ = h.Write(page[:hashEnd])
return h.Sum64()
func setPage(page []byte)
randPage(page)
hashEnd := len(page) - int(unsafe.Sizeof(uint64(0)))
dPtr := (*uint64)(unsafe.Pointer(&page[hashEnd]))
*dPtr = hashPage(page)
func main()
pageFile := "/tmp/page.db"
if _, err := os.Stat(pageFile); err == nil
os.Remove(pageFile)
pageSize := syscall.Getpagesize()
fmt.Printf("page size = %d \\n", pageSize)
fd, err := os.OpenFile(pageFile, os.O_RDWR|os.O_CREATE, 0644)
if err != nil
log.Fatal(err)
defer fd.Close()
ref, err := syscall.Mmap(int(fd.Fd()), 0, pageSize, syscall.PROT_READ, syscall.MAP_SHARED)
if err != nil
log.Fatal(err)
defer syscall.Munmap(ref)
page := make([]byte, pageSize)
setPage(page)
if n, err := fd.WriteAt(page, 0); n != pageSize || err != nil
log.Fatal(err)
if err := syscall.Fsync(int(fd.Fd())); err != nil
log.Fatal(err)
ch := make(chan struct)
var wg sync.WaitGroup
wg.Add(1)
go func()
defer wg.Done()
hashEnd := pageSize - int(unsafe.Sizeof(uint64(0)))
dPtr := (*uint64)(unsafe.Pointer(&ref[hashEnd]))
ret := false
cnt := 0
var initHash uint64
initHash = 0
for
if ret
log.Printf("read count = %d\\n", cnt)
return
h1 := hashPage(ref)
if initHash == h1
log.Printf("same hash value, i = %x, h = %x\\n", initHash, h1)
initHash = h1
if *dPtr != h1
log.Fatalf("check sum error, h = %x, d = %x\\n", h1, *dPtr)
select
case <-ch:
ret = true
default:
cnt++
()
wg.Add(1)
go func()
defer wg.Done()
for i := 0; i < 100000; i++
setPage(page)
if n, err := fd.WriteAt(page, 0); n != pageSize || err != nil
log.Fatal(err)
if err := syscall.Fsync(int(fd.Fd())); err != nil
log.Fatal(err)
ch <- struct
()
wg.Wait()
程序输出结果如下:
2020/08/28 10:51:24 same hash value, i = fa854bd3b8edaf60, h = fa854bd3b8edaf60
2020/08/28 10:51:24 check sum error, h = 2202313290c04b15, d = d82723c176e773c1
exit status 1
以上是关于[linux] page 写磁盘并不是原子性的主要内容,如果未能解决你的问题,请参考以下文章