해킹이라 썼는데 훼이크임. 그냥 있어보여서.
go 쪼렙입니다. 며칠 안 됐어요.
여튼, go에서 복사와 자동 힙 할당을 피하고자 포인터 연산처럼 다룰려면 꽤 복잡한데 다음과 같이 쓴다.
header := (*reflect.SliceHeader)(unsafe.Pointer(&my_data[0].pos1))
header.Len = 1024
header.Cap = 1024
unix.Msync(*(*[]byte)(unsafe.Pointer(header)), unix.MS_SYNC)
my_data 구조체의 특정위치를 슬라이스 헤더 형태에 넣고, 이것을 원하는 형태로 디리퍼런싱 하면 되는데.. 영 껄끄럽다.
여튼 이때 주의사항은 header가 다음과 같이 구성되어 있다는 것이다.
주소 8바이트
길이 8바이트
용량 8바이트
아키에 따라서 다를지도 모른다. 나도 몰러. 헥사로 봤을 때 자료형을 안내하는 메타는 보이지 않았다.. 아마도 정적타입 언어라서 컴파일 타임때 전부 지지고 볶고 할 듯..
위에서 사용한 my_data 구조체가 다음과 같다고 치자.
type data_file struct {
pos1 int
d [MAX_ITEM]data
}
이러면 pos1 자리를 header로 잡는 순간 Len, Cap이 d를 덮어쓴다. 하아..
따라서 더미공간을 남겨둬야 한다. 나는 mmap 빠돌이니까 4킬로 단위의 더미를 넣었다. go에도 이런 짓을 할지는 몰랐다.
type data_file struct {
pos1 int
dummy1 [4096 - INT_SIZE]byte
d [MAX_ITEM]data
}
더미에 header의 Len, Cap을 쓰는데 남이사다. 나는 다시 쓸 일 없다. 가만.. 어? 이걸 가지고 프로토버프 느낌이 나면서 슬라이스 직때려넣기 동적 타이핑이 되겠는데?? (나중에 연구해야지..)
실제로는 msync로 mmap page 캐시를 강제 디스크 동기화하려고 써봤다.
header = (*reflect.SliceHeader)(unsafe.Pointer(&my_data[0].pos2))
header.Len = 4096 - 8
header.Cap = 4096 - 8
unix.Msync(*(*[]byte)(unsafe.Pointer(header)), unix.MS_SYNC)
아마도 go에서는 더 go스러운 우아한 패턴이 있을 것 같은데 쪼렙이라 모른다. 책을 하나 샀는데 고 프로그래밍 뭐더라.. 책이 집에 있다. 아마도 거기에도 안 나올 듯. 쪼렙책 산 듯..