[t:/]$ 지식_

go 파일 저장 스택의 인터페이스 버전

2020/06/24

몇 줄 바꿔봤다. 원래는

푸시/팝에서 형을 지정하지 않고 인터페이스를 썼다. void * 구만?
대충 뮤텍스로 감쌌음..

package main

import (
    "unsafe"
    "os"
    "fmt"
    "syscall"
    "reflect"
//  "flag"
    "golang.org/x/sys/unix"
    "sync"
    "time"
)

var mutex = &sync.Mutex{}

const DATA_SIZE int = 16

type data struct {
//  klen int
    v [DATA_SIZE]byte
}

const INT_SIZE  int = int(unsafe.Sizeof(int(0)))
const MAX_ITEM  int = 1000000
const ITEM_SIZE int = int(unsafe.Sizeof(data{}))
const FILE_SIZE int = ITEM_SIZE * MAX_ITEM

type data_file struct {
    pos1 int
    dummy1 [4096 - INT_SIZE]byte
    items [MAX_ITEM]data
    dummy3 [4096 - (MAX_ITEM * ITEM_SIZE) % 4096]byte
    pos2 int
    dummy2 [4096 - INT_SIZE]byte    
}

func Open_data(init bool, filename string) []data_file {

    size := int(unsafe.Sizeof( data_file{} ))
    println(size)

    var map_file *os.File
    var err error

    if init {

        map_file, err = os.Create(filename)

    } else {
        map_file, err = os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_SYNC, 0755)
    }

    defer map_file.Close()

    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    _, err = map_file.Seek(int64(size - 1), 0)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    _, err = map_file.Write([]byte{0})
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    mmap, err := syscall.Mmap(int(map_file.Fd()), 0, int(size), syscall.PROT_READ | syscall.PROT_WRITE, syscall.MAP_SHARED)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    if init {
        for i := range mmap {
            mmap[i] = 0
        }
    }

    header := (*reflect.SliceHeader)(unsafe.Pointer(&mmap))
    header.Len = 1
    header.Cap = 1

    map_data := *(*[]data_file)(unsafe.Pointer(header))

    err = map_file.Close()    

    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }    

    return map_data
}

func Close_data(mmap []data_file) {

    header := (*reflect.SliceHeader)(unsafe.Pointer(&mmap))
    header.Len = int(unsafe.Sizeof(data_file{}))
    header.Cap = header.Len 

    unmap := *(*[]byte)(unsafe.Pointer(&mmap))
    err := syscall.Munmap(unmap)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
}

var sp int = 0
var gpos1 *int
var gpos2 *int
var max_pos *int

//func push(item_data []byte, store []data_file ) {
func push(item_data interface{}, store []data_file ) {

    var item_byte []byte

    switch item_data.(type) {
        case []byte:
            item_byte = item_data.([]byte)
        case string:
            item_byte = []byte(item_data.(string))
        default:

    }

//  item_byte := item_data.([]byte)
    item_byte = append(item_byte, 0)

    mutex.Lock()

    if sp == MAX_ITEM {
        fmt.Fprintf(os.Stderr, "용량 초과, 마지막 푸시 = %s\n", string(item_byte))
        return
    }

    copy(store[0].items[*gpos1].v[:], item_byte)
    *gpos1++
    *gpos2++
    sp++

    mutex.Unlock()

}

func pop(store []data_file ) (ret interface{}) {

    mutex.Lock()

    sp--

    if sp < 0 {
//      ret = []byte("")
        ret = nil
        fmt.Fprintf(os.Stderr, "스택이 비었음\n")
        sp = 0
        return 
    }

    *gpos1--
    *gpos2--    

    ret = store[0].items[*gpos1].v[:]

    mutex.Unlock()

    return 
}

func main() {

    println(FILE_SIZE)

//  file := flag.String("file", "stack.dat", "스택 저장소 파일 이름")
//  max_items := flag.Int("max-item", MAX_ITEM, "최대 아이템 갯수")
//  bucket_size := flag.Int("bucket-size", DATA_SIZE, "버킷 크기")

    my_data := Open_data(true, "my_data.dat")

    header := (*reflect.SliceHeader)(unsafe.Pointer(&my_data[0].pos1))
    header.Len = 4096
    header.Cap = 4096

    unix.Msync(*(*[]byte)(unsafe.Pointer(header)), unix.MS_SYNC)

    header = (*reflect.SliceHeader)(unsafe.Pointer(&my_data[0].pos2))
    header.Len = 4096
    header.Cap = 4096

    unix.Msync(*(*[]byte)(unsafe.Pointer(header)), unix.MS_SYNC)    

    gpos1 = &my_data[0].pos1
    gpos2 = &my_data[0].pos2
    sp = *gpos1

    for i := 0; i < 10000; i++ {
        go push(fmt.Sprintf("-- %d --", i), my_data)
    }

    time.Sleep(time.Duration(1) * time.Second)

    for i := 0; i < 10000; i++ {
        go func() {
            a := pop(my_data)
            if a != nil {
                println(string(a.([]byte)))
            }
        } ()
    }

    time.Sleep(time.Duration(4) * time.Second)

//  println(string(pop(my_data).([]byte)))

    os.Exit(0)

//  println(string(pop(my_data).([]byte)))

//  os.Exit(0)

    push("가나", my_data)
    println(string(pop(my_data).([]byte)))

    push([]byte("가나--"), my_data)
    println(string(pop(my_data).([]byte)))

//  push(다라"), my_data)
    push([]byte("마바"), my_data)
    push([]byte("하하"), my_data)
    push([]byte("호호"), my_data)

    println(string(pop(my_data).([]byte)))
    println(string(pop(my_data).([]byte)))
    println()

    push([]byte("추가1"), my_data)
    push([]byte("추가2"), my_data)

    println(string(pop(my_data).([]byte)))

/*  
    for {

        a := pop(my_data)

        if a != nil {
            println(string(a))
        } else {
            break
        }
    }
*/  
    defer Close_data(my_data)

}








[t:/] is not "technology - root". dawnsea, rss