@@ -22,90 +22,107 @@ import (
22
22
// [EXCLUSIVE locking mode]: https://sqlite.org/pragma.html#pragma_locking_mode
23
23
const SupportsSharedMemory = true
24
24
25
- type vfsShm struct {
26
- * os.File
27
- regions []* util.MappedRegion
28
- }
29
-
30
25
const (
31
26
_SHM_NLOCK = 8
32
27
_SHM_BASE = 120
33
28
_SHM_DMS = _SHM_BASE + _SHM_NLOCK
34
29
)
35
30
36
- func (f * vfsFile ) SharedMemory () SharedMemory { return f }
31
+ func (f * vfsFile ) SharedMemory () SharedMemory { return f .shm }
32
+
33
+ // NewSharedMemory returns a shared-memory WAL-index
34
+ // backed a file with the given path.
35
+ // It may return nil if shared-memory is not supported,
36
+ // or not appropriate for the given flags.
37
+ // Only [OPEN_MAIN_DB] databases support WAL mode.
38
+ func NewSharedMemory (path string , flags OpenFlag ) SharedMemory {
39
+ if flags & OPEN_MAIN_DB == 0 {
40
+ return nil
41
+ }
42
+ return & vfsShm {
43
+ path : path ,
44
+ readOnly : flags & OPEN_READONLY != 0 ,
45
+ }
46
+ }
47
+
48
+ type vfsShm struct {
49
+ * os.File
50
+ regions []* util.MappedRegion
51
+ path string
52
+ readOnly bool
53
+ }
37
54
38
- func (f * vfsFile ) shmMap (ctx context.Context , mod api.Module , id , size int32 , extend bool ) (uint32 , error ) {
55
+ func (s * vfsShm ) shmMap (ctx context.Context , mod api.Module , id , size int32 , extend bool ) (uint32 , error ) {
39
56
// Ensure size is a multiple of the OS page size.
40
57
if int (size )& (unix .Getpagesize ()- 1 ) != 0 {
41
58
return 0 , _IOERR_SHMMAP
42
59
}
43
60
44
- if f . shm .File == nil {
61
+ if s .File == nil {
45
62
var flag int
46
- if f .readOnly {
63
+ if s .readOnly {
47
64
flag = unix .O_RDONLY
48
65
} else {
49
66
flag = unix .O_RDWR
50
67
}
51
- s , err := os .OpenFile (f . Name () + "-shm" ,
68
+ f , err := os .OpenFile (s . path ,
52
69
flag | unix .O_CREAT | unix .O_NOFOLLOW , 0666 )
53
70
if err != nil {
54
71
return 0 , _CANTOPEN
55
72
}
56
- f . shm . File = s
73
+ s . File = f
57
74
}
58
75
59
76
// Dead man's switch.
60
- if lock , rc := osGetLock (f . shm .File , _SHM_DMS , 1 ); rc != _OK {
77
+ if lock , rc := osGetLock (s .File , _SHM_DMS , 1 ); rc != _OK {
61
78
return 0 , _IOERR_LOCK
62
79
} else if lock == unix .F_WRLCK {
63
80
return 0 , _BUSY
64
81
} else if lock == unix .F_UNLCK {
65
- if f .readOnly {
82
+ if s .readOnly {
66
83
return 0 , _READONLY_CANTINIT
67
84
}
68
- if rc := osWriteLock (f . shm .File , _SHM_DMS , 1 , 0 ); rc != _OK {
85
+ if rc := osWriteLock (s .File , _SHM_DMS , 1 , 0 ); rc != _OK {
69
86
return 0 , rc
70
87
}
71
- if err := f . shm .Truncate (0 ); err != nil {
88
+ if err := s .Truncate (0 ); err != nil {
72
89
return 0 , _IOERR_SHMOPEN
73
90
}
74
91
}
75
- if rc := osReadLock (f . shm .File , _SHM_DMS , 1 , 0 ); rc != _OK {
92
+ if rc := osReadLock (s .File , _SHM_DMS , 1 , 0 ); rc != _OK {
76
93
return 0 , rc
77
94
}
78
95
79
96
// Check if file is big enough.
80
- s , err := f . shm .Seek (0 , io .SeekEnd )
97
+ o , err := s .Seek (0 , io .SeekEnd )
81
98
if err != nil {
82
99
return 0 , _IOERR_SHMSIZE
83
100
}
84
- if n := (int64 (id ) + 1 ) * int64 (size ); n > s {
101
+ if n := (int64 (id ) + 1 ) * int64 (size ); n > o {
85
102
if ! extend {
86
103
return 0 , nil
87
104
}
88
- err := osAllocate (f . shm .File , n )
105
+ err := osAllocate (s .File , n )
89
106
if err != nil {
90
107
return 0 , _IOERR_SHMSIZE
91
108
}
92
109
}
93
110
94
111
var prot int
95
- if f .readOnly {
112
+ if s .readOnly {
96
113
prot = unix .PROT_READ
97
114
} else {
98
115
prot = unix .PROT_READ | unix .PROT_WRITE
99
116
}
100
- r , err := util .MapRegion (ctx , mod , f . shm .File , int64 (id )* int64 (size ), size , prot )
117
+ r , err := util .MapRegion (ctx , mod , s .File , int64 (id )* int64 (size ), size , prot )
101
118
if err != nil {
102
119
return 0 , err
103
120
}
104
- f . shm . regions = append (f . shm .regions , r )
121
+ s . regions = append (s .regions , r )
105
122
return r .Ptr , nil
106
123
}
107
124
108
- func (f * vfsFile ) shmLock (offset , n int32 , flags _ShmFlag ) error {
125
+ func (s * vfsShm ) shmLock (offset , n int32 , flags _ShmFlag ) error {
109
126
// Argument check.
110
127
if n <= 0 || offset < 0 || offset + n > _SHM_NLOCK {
111
128
panic (util .AssertErr ())
@@ -126,28 +143,28 @@ func (f *vfsFile) shmLock(offset, n int32, flags _ShmFlag) error {
126
143
127
144
switch {
128
145
case flags & _SHM_UNLOCK != 0 :
129
- return osUnlock (f . shm .File , _SHM_BASE + int64 (offset ), int64 (n ))
146
+ return osUnlock (s .File , _SHM_BASE + int64 (offset ), int64 (n ))
130
147
case flags & _SHM_SHARED != 0 :
131
- return osReadLock (f . shm .File , _SHM_BASE + int64 (offset ), int64 (n ), 0 )
148
+ return osReadLock (s .File , _SHM_BASE + int64 (offset ), int64 (n ), 0 )
132
149
case flags & _SHM_EXCLUSIVE != 0 :
133
- return osWriteLock (f . shm .File , _SHM_BASE + int64 (offset ), int64 (n ), 0 )
150
+ return osWriteLock (s .File , _SHM_BASE + int64 (offset ), int64 (n ), 0 )
134
151
default :
135
152
panic (util .AssertErr ())
136
153
}
137
154
}
138
155
139
- func (f * vfsFile ) shmUnmap (delete bool ) {
156
+ func (s * vfsShm ) shmUnmap (delete bool ) {
140
157
// Unmap regions.
141
- for _ , r := range f . shm .regions {
158
+ for _ , r := range s .regions {
142
159
r .Unmap ()
143
160
}
144
- clear (f . shm .regions )
145
- f . shm . regions = f . shm .regions [:0 ]
161
+ clear (s .regions )
162
+ s . regions = s .regions [:0 ]
146
163
147
164
// Close the file.
148
- if delete && f . shm .File != nil {
149
- os .Remove (f . shm .Name ())
165
+ if delete && s .File != nil {
166
+ os .Remove (s .Name ())
150
167
}
151
- f . shm .Close ()
152
- f . shm .File = nil
168
+ s .Close ()
169
+ s .File = nil
153
170
}
0 commit comments