aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--weed/storage/memory_map_windows.go216
1 files changed, 216 insertions, 0 deletions
diff --git a/weed/storage/memory_map_windows.go b/weed/storage/memory_map_windows.go
new file mode 100644
index 000000000..a6c96caaf
--- /dev/null
+++ b/weed/storage/memory_map_windows.go
@@ -0,0 +1,216 @@
+// +build windows
+
+package storage
+
+import (
+ "reflect"
+ "syscall"
+ "unsafe"
+
+ "golang.org/x/sys/windows"
+)
+
+type DWORD = uint32
+type WORD = uint16
+
+type memory_buffer struct {
+ aligned_length uint64
+ length uint64
+ aligned_ptr uintptr
+ ptr uintptr
+ buffer []byte
+}
+
+type memory_map struct {
+ file_handle windows.Handle
+ file_memory_map_handle windows.Handle
+ write_map_views []memory_buffer
+ max_length uint64
+ // read_map_views []memory_buffer
+}
+
+var (
+ procGetSystemInfo = syscall.NewLazyDLL("kernel32.dll").NewProc("GetSystemInfo")
+)
+
+var system_info, err = getSystemInfo()
+
+var chunk_size = uint64(system_info.dwAllocationGranularity) * 512
+
+func CreateMemoryMap(hFile windows.Handle, maxlength uint64) memory_map {
+
+ mem_map := memory_map{}
+ maxlength_high := uint32(maxlength >> 32)
+ maxlength_low := uint32(maxlength & 0xFFFFFFFF)
+ file_memory_map_handle, err := windows.CreateFileMapping(hFile, nil, windows.PAGE_READWRITE, maxlength_high, maxlength_low, nil)
+
+ if err != nil {
+ mem_map.file_handle = hFile
+ mem_map.file_memory_map_handle = file_memory_map_handle
+ mem_map.max_length = maxlength
+ }
+
+ return mem_map
+}
+
+func DeleteFileAndMemoryMap(mem_map memory_map) {
+ windows.CloseHandle(mem_map.file_memory_map_handle)
+ windows.CloseHandle(mem_map.file_handle)
+
+ for _, view := range mem_map.write_map_views {
+ ReleaseMemory(view)
+ }
+
+ mem_map.write_map_views = nil
+ mem_map.max_length = 0
+}
+
+func min(x, y uint64) uint64 {
+ if x < y {
+ return x
+ }
+ return y
+}
+
+func WriteMemory(mem_map memory_map, offset uint64, length uint64, data []byte) {
+
+ for {
+ if ((offset+length)/chunk_size)+1 > uint64(len(mem_map.write_map_views)) {
+ allocateChunk(mem_map)
+ } else {
+ break
+ }
+ }
+
+ remaining_length := length
+ slice_index := offset / chunk_size
+ slice_offset := offset - (slice_index * chunk_size)
+ data_offset := uint64(0)
+
+ for {
+ write_end := min(remaining_length, chunk_size)
+ copy(mem_map.write_map_views[slice_index].buffer[slice_offset:write_end], data[data_offset:])
+ remaining_length -= (write_end - slice_offset)
+ data_offset += (write_end - slice_offset)
+
+ if remaining_length > 0 {
+ slice_index += 1
+ slice_offset = 0
+ } else {
+ break
+ }
+ }
+}
+
+func ReadMemory(mem_map memory_map, offset uint64, length uint64) (memory_buffer, error) {
+ return allocate(mem_map.file_memory_map_handle, offset, length, false)
+}
+
+func ReleaseMemory(mem_buffer memory_buffer) {
+ windows.UnmapViewOfFile(mem_buffer.aligned_ptr)
+
+ mem_buffer.ptr = 0
+ mem_buffer.aligned_ptr = 0
+ mem_buffer.length = 0
+ mem_buffer.aligned_length = 0
+ mem_buffer.buffer = nil
+}
+
+func allocateChunk(mem_map memory_map) {
+
+ start := uint64(len(mem_map.write_map_views)-1) * chunk_size
+ mem_buffer, err := allocate(mem_map.file_memory_map_handle, start, chunk_size, true)
+
+ if err == nil {
+ mem_map.write_map_views = append(mem_map.write_map_views, mem_buffer)
+ }
+}
+
+func allocate(hMapFile windows.Handle, offset uint64, length uint64, write bool) (memory_buffer, error) {
+
+ mem_buffer := memory_buffer{}
+
+ dwSysGran := system_info.dwAllocationGranularity
+
+ start := (offset / uint64(dwSysGran)) * uint64(dwSysGran)
+ diff := offset - start
+ aligned_length := diff + length
+
+ offset_high := uint32(start >> 32)
+ offset_low := uint32(start & 0xFFFFFFFF)
+
+ access := windows.FILE_MAP_READ
+
+ if write {
+ access = windows.FILE_MAP_WRITE
+ }
+
+ addr_ptr, errno := windows.MapViewOfFile(hMapFile,
+ uint32(access), // read/write permission
+ offset_high,
+ offset_low,
+ uintptr(aligned_length))
+
+ if addr_ptr == 0 {
+ return mem_buffer, errno
+ }
+
+ mem_buffer.aligned_ptr = addr_ptr
+ mem_buffer.aligned_length = aligned_length
+ mem_buffer.ptr = addr_ptr + uintptr(diff)
+ mem_buffer.length = length
+
+ slice_header := (*reflect.SliceHeader)(unsafe.Pointer(&mem_buffer.buffer))
+ slice_header.Data = addr_ptr + uintptr(diff)
+ slice_header.Len = int(length)
+ slice_header.Cap = int(length)
+
+ return mem_buffer, nil
+}
+
+// typedef struct _SYSTEM_INFO {
+// union {
+// DWORD dwOemId;
+// struct {
+// WORD wProcessorArchitecture;
+// WORD wReserved;
+// };
+// };
+// DWORD dwPageSize;
+// LPVOID lpMinimumApplicationAddress;
+// LPVOID lpMaximumApplicationAddress;
+// DWORD_PTR dwActiveProcessorMask;
+// DWORD dwNumberOfProcessors;
+// DWORD dwProcessorType;
+// DWORD dwAllocationGranularity;
+// WORD wProcessorLevel;
+// WORD wProcessorRevision;
+// } SYSTEM_INFO;
+// https://msdn.microsoft.com/en-us/library/ms724958(v=vs.85).aspx
+type _SYSTEM_INFO struct {
+ dwOemId DWORD
+ dwPageSize DWORD
+ lpMinimumApplicationAddress uintptr
+ lpMaximumApplicationAddress uintptr
+ dwActiveProcessorMask uintptr
+ dwNumberOfProcessors DWORD
+ dwProcessorType DWORD
+ dwAllocationGranularity DWORD
+ wProcessorLevel WORD
+ wProcessorRevision WORD
+}
+
+// void WINAPI GetSystemInfo(
+// _Out_ LPSYSTEM_INFO lpSystemInfo
+// );
+// https://msdn.microsoft.com/en-us/library/ms724381(VS.85).aspx
+func getSystemInfo() (_SYSTEM_INFO, error) {
+ var si _SYSTEM_INFO
+ _, _, err := procGetSystemInfo.Call(
+ uintptr(unsafe.Pointer(&si)),
+ )
+ if err != syscall.Errno(0) {
+ return si, err
+ }
+ return si, nil
+}