41
|
1
|
;;; io/blob.lisp --- Blob Database IO |
|
2
|
|
|
3
|
;; |
|
4
|
|
|
5
|
;;; Code: |
|
6
|
(in-package :xdb) |
|
7
|
|
|
8
|
;;; IO |
|
9
|
(defvar *fsync-data* nil) |
|
10
|
|
|
11
|
(defconstant +buffer-size+ 8192) |
|
12
|
|
|
13
|
(deftype word () 'sb-ext:word) |
|
14
|
|
|
15
|
(defstruct (input-stream |
|
16
|
(:predicate nil)) |
|
17
|
(fd nil :type word) |
|
18
|
(left 0 :type word) |
|
19
|
(buffer-start (sb-sys:sap-int |
|
20
|
(sb-alien::%make-alien (* sb-vm:n-byte-bits |
|
21
|
(+ +buffer-size+ 3)))) |
|
22
|
:type word) |
|
23
|
(buffer-end 0 :type word) |
|
24
|
(buffer-position 0 :type word)) |
|
25
|
|
|
26
|
(defstruct (output-stream |
|
27
|
(:predicate nil)) |
|
28
|
(fd nil :type word) |
|
29
|
(buffer-start (sb-sys:sap-int |
|
30
|
(sb-alien::%make-alien (* sb-vm:n-byte-bits |
|
31
|
(+ +buffer-size+ 3)))) |
|
32
|
:type word) |
|
33
|
(buffer-end 0 :type word) |
|
34
|
(buffer-position 0 :type word)) |
|
35
|
|
|
36
|
(defun open-file (file-stream |
|
37
|
&key direction) |
|
38
|
(if (eql direction :output) |
|
39
|
(let ((output (make-output-stream |
|
40
|
:fd (sb-sys:fd-stream-fd file-stream)))) |
|
41
|
(setf (output-stream-buffer-position output) |
|
42
|
(output-stream-buffer-start output) |
|
43
|
(output-stream-buffer-end output) |
|
44
|
(+ (output-stream-buffer-start output) |
|
45
|
+buffer-size+)) |
|
46
|
output) |
|
47
|
(make-input-stream |
|
48
|
:fd (sb-sys:fd-stream-fd file-stream) |
|
49
|
:left (file-length file-stream)))) |
|
50
|
|
|
51
|
(defun close-input-stream (stream) |
|
52
|
(sb-alien:alien-funcall |
|
53
|
(sb-alien:extern-alien "free" |
|
54
|
(function (values) sb-alien:long)) |
|
55
|
(input-stream-buffer-start stream))) |
|
56
|
|
|
57
|
(defun close-output-stream (stream) |
|
58
|
(flush-buffer stream) |
|
59
|
(sb-alien:alien-funcall |
|
60
|
(sb-alien:extern-alien "free" |
|
61
|
(function (values) sb-alien:long)) |
|
62
|
(output-stream-buffer-start stream))) |
|
63
|
|
|
64
|
(declaim (inline stream-end-of-file-p)) |
|
65
|
(defun stream-end-of-file-p (stream) |
|
66
|
(and (>= (input-stream-buffer-position stream) |
|
67
|
(input-stream-buffer-end stream)) |
|
68
|
(zerop (input-stream-left stream)))) |
|
69
|
|
|
70
|
(declaim (inline sap-ref-24)) |
|
71
|
(defun sap-ref-24 (sap offset) |
|
72
|
(declare (optimize speed (safety 0)) |
|
73
|
(fixnum offset)) |
|
74
|
(mask-field (byte 24 0) (sb-sys:sap-ref-32 sap offset))) |
|
75
|
|
|
76
|
(declaim (inline n-sap-ref)) |
|
77
|
(defun n-sap-ref (n sap &optional (offset 0)) |
|
78
|
(funcall (ecase n |
|
79
|
(1 #'sb-sys:sap-ref-8) |
|
80
|
(2 #'sb-sys:sap-ref-16) |
|
81
|
(3 #'sap-ref-24) |
|
82
|
(4 #'sb-sys:sap-ref-32)) |
|
83
|
sap |
|
84
|
offset)) |
|
85
|
|
|
86
|
(declaim (inline unix-read)) |
|
87
|
(defun unix-read (fd buf len) |
|
88
|
(declare (optimize (sb-c::float-accuracy 0) |
|
89
|
(space 0))) |
|
90
|
(declare (type sb-unix::unix-fd fd) |
|
91
|
(type word len)) |
|
92
|
(sb-alien:alien-funcall |
|
93
|
(sb-alien:extern-alien "read" |
|
94
|
(function sb-alien:int |
|
95
|
sb-alien:int sb-alien:long sb-alien:int)) |
|
96
|
fd buf len)) |
|
97
|
|
|
98
|
(declaim (inline unix-read)) |
|
99
|
(defun unix-write (fd buf len) |
|
100
|
(declare (optimize (sb-c::float-accuracy 0) |
|
101
|
(space 0))) |
|
102
|
(declare (type sb-unix::unix-fd fd) |
|
103
|
(type word len)) |
|
104
|
(sb-alien:alien-funcall |
|
105
|
(sb-alien:extern-alien "write" |
|
106
|
(function sb-alien:int |
|
107
|
sb-alien:int sb-alien:long sb-alien:int)) |
|
108
|
fd buf len)) |
|
109
|
|
|
110
|
(defun fill-buffer (stream offset) |
|
111
|
(let ((length (unix-read (input-stream-fd stream) |
|
112
|
(+ (input-stream-buffer-start stream) offset) |
|
113
|
(- +buffer-size+ offset)))) |
|
114
|
(setf (input-stream-buffer-end stream) |
|
115
|
(+ (input-stream-buffer-start stream) (+ length offset))) |
|
116
|
(decf (input-stream-left stream) length)) |
|
117
|
t) |
|
118
|
|
|
119
|
(defun refill-buffer (n stream) |
|
120
|
(declare (type word n) |
|
121
|
(input-stream stream)) |
|
122
|
(let ((left-n-bytes (- (input-stream-buffer-end stream) |
|
123
|
(input-stream-buffer-position stream)))) |
|
124
|
(when (> (- n left-n-bytes) |
|
125
|
(input-stream-left stream)) |
|
126
|
(error "End of file ~a" stream)) |
|
127
|
(unless (zerop left-n-bytes) |
|
128
|
(setf (sb-sys:sap-ref-word (sb-sys:int-sap (input-stream-buffer-start stream)) 0) |
|
129
|
(n-sap-ref left-n-bytes (sb-sys:int-sap (input-stream-buffer-position stream))))) |
|
130
|
(fill-buffer stream left-n-bytes)) |
|
131
|
(let ((start (input-stream-buffer-start stream))) |
|
132
|
(setf (input-stream-buffer-position stream) |
|
133
|
(+ start n))) |
|
134
|
t) |
|
135
|
|
|
136
|
(declaim (inline advance-input-stream)) |
|
137
|
(defun advance-input-stream (n stream) |
|
138
|
(declare (optimize (space 0)) |
|
139
|
(type word n) |
|
140
|
(type input-stream stream)) |
|
141
|
(let* ((sap (input-stream-buffer-position stream)) |
|
142
|
(new-sap (sb-ext:truly-the word (+ sap n)))) |
|
143
|
(declare (word sap new-sap)) |
|
144
|
(cond ((> new-sap (input-stream-buffer-end stream)) |
|
145
|
(refill-buffer n stream) |
|
146
|
(sb-sys:int-sap (input-stream-buffer-start stream))) |
|
147
|
(t |
|
148
|
(setf (input-stream-buffer-position stream) |
|
149
|
new-sap) |
|
150
|
(sb-sys:int-sap sap))))) |
|
151
|
|
|
152
|
(declaim (inline read-n-bytes)) |
|
153
|
(defun read-n-bytes (n stream) |
|
154
|
(declare (optimize (space 0)) |
|
155
|
(type word n)) |
|
156
|
(n-sap-ref n (advance-input-stream n stream))) |
|
157
|
|
|
158
|
(declaim (inline read-n-signed-bytes)) |
|
159
|
(defun read-n-signed-bytes (n stream) |
|
160
|
(declare (optimize speed) |
|
161
|
(sb-ext:muffle-conditions sb-ext:compiler-note) |
|
162
|
(type (integer 1 4) n)) |
|
163
|
(funcall (ecase n |
|
164
|
(1 #'sb-sys:signed-sap-ref-8) |
|
165
|
(2 #'sb-sys:signed-sap-ref-16) |
|
166
|
;; (3 ) |
|
167
|
(4 #'sb-sys:signed-sap-ref-32)) |
|
168
|
(advance-input-stream n stream) |
|
169
|
0)) |
|
170
|
|
|
171
|
(declaim (inline write-n-signed-bytes)) |
|
172
|
(defun write-n-signed-bytes (value n stream) |
|
173
|
(declare (optimize speed) |
|
174
|
(sb-ext:muffle-conditions sb-ext:compiler-note) |
|
175
|
(fixnum n)) |
|
176
|
(ecase n |
|
177
|
(1 (setf (sb-sys:signed-sap-ref-8 (advance-output-stream n stream) 0) |
|
178
|
value)) |
|
179
|
(2 (setf (sb-sys:signed-sap-ref-16 (advance-output-stream n stream) 0) |
|
180
|
value)) |
|
181
|
;; (3 ) |
|
182
|
(4 (setf (sb-sys:signed-sap-ref-32 (advance-output-stream n stream) 0) |
|
183
|
value))) |
|
184
|
t) |
|
185
|
|
|
186
|
(defun flush-buffer (stream) |
|
187
|
(unix-write (output-stream-fd stream) |
|
188
|
(output-stream-buffer-start stream) |
|
189
|
(- (output-stream-buffer-position stream) |
|
190
|
(output-stream-buffer-start stream)))) |
|
191
|
|
|
192
|
(declaim (inline advance-output-stream)) |
|
193
|
(defun advance-output-stream (n stream) |
|
194
|
(declare (optimize (space 0) (safety 0)) |
|
195
|
(type word n) |
|
196
|
(type output-stream stream) |
|
197
|
((integer 1 4) n)) |
|
198
|
(let* ((sap (output-stream-buffer-position stream)) |
|
199
|
(new-sap (sb-ext:truly-the word (+ sap n)))) |
|
200
|
(declare (word sap new-sap)) |
|
201
|
(cond ((> new-sap (output-stream-buffer-end stream)) |
|
202
|
(flush-buffer stream) |
|
203
|
(setf (output-stream-buffer-position stream) |
|
204
|
(+ (output-stream-buffer-start stream) |
|
205
|
n)) |
|
206
|
(sb-sys:int-sap (output-stream-buffer-start stream))) |
|
207
|
(t |
|
208
|
(setf (output-stream-buffer-position stream) |
|
209
|
new-sap) |
|
210
|
(sb-sys:int-sap sap))))) |
|
211
|
|
|
212
|
(declaim (inline write-n-bytes)) |
|
213
|
(defun write-n-bytes (value n stream) |
|
214
|
(declare (optimize (space 0)) |
|
215
|
(type word n)) |
|
216
|
(setf (sb-sys:sap-ref-32 |
|
217
|
(advance-output-stream n stream) |
|
218
|
0) |
|
219
|
value)) |
|
220
|
;;; |
|
221
|
|
|
222
|
(declaim (inline copy-mem)) |
|
223
|
(defun copy-mem (from to length) |
|
224
|
(let ((words-end (- length (rem length sb-vm:n-word-bytes)))) |
|
225
|
(loop for i by sb-vm:n-word-bytes below words-end |
|
226
|
do (setf (sb-sys:sap-ref-word to i) |
|
227
|
(sb-sys:sap-ref-word from i))) |
|
228
|
(loop for i from words-end below length |
|
229
|
do (setf (sb-sys:sap-ref-8 to i) |
|
230
|
(sb-sys:sap-ref-8 from i))))) |
|
231
|
|
|
232
|
(declaim (inline read-ascii-string-optimized)) |
|
233
|
(defun read-ascii-string-optimized (length string stream) |
|
234
|
(declare (type fixnum length) |
|
235
|
(optimize (speed 3)) |
|
236
|
) |
|
237
|
(sb-sys:with-pinned-objects (string) |
|
238
|
(let ((sap (advance-input-stream length stream)) |
|
239
|
(string-sap (sb-sys:vector-sap string))) |
|
240
|
(copy-mem sap string-sap length))) |
|
241
|
string) |
|
242
|
(defmacro with-io-file ((stream file |
|
243
|
&key append (direction :input)) |
|
244
|
&body body) |
|
245
|
(let ((fd-stream (gensym))) |
|
246
|
`(with-open-file (,fd-stream ,file |
|
247
|
:element-type '(unsigned-byte 8) |
|
248
|
:direction ,direction |
|
249
|
,@(and (eql direction :output) |
|
250
|
`(:if-exists ,(if append |
|
251
|
:append |
|
252
|
:supersede))) |
|
253
|
,@(and append |
|
254
|
`(:if-does-not-exist :create))) |
|
255
|
(let ((,stream (open-file ,fd-stream :direction ,direction))) |
|
256
|
(unwind-protect |
|
257
|
(progn ,@body) |
|
258
|
,@(ecase direction |
|
259
|
(:output |
|
260
|
`((close-output-stream ,stream) |
|
261
|
(when *fsync-data* |
|
262
|
(sb-posix:fdatasync |
|
263
|
(sb-sys:fd-stream-fd ,fd-stream))))) |
|
264
|
(:input |
|
265
|
`((close-input-stream ,stream))))))))) |