5fd33b9560
This works 1 byte at a time so will be slow.
173 lines
4.6 KiB
Scheme
173 lines
4.6 KiB
Scheme
(library
|
|
;; We can't call this (bcache bcache) because it'll clash with the C lib
|
|
(bcache block-manager)
|
|
(export with-bcache
|
|
get-nr-blocks
|
|
get-nr-locked
|
|
get-block
|
|
block-data
|
|
block-index
|
|
release-block
|
|
flush-cache
|
|
get-flags
|
|
prefetch-block
|
|
with-block
|
|
spine
|
|
spine-exit
|
|
spine-step
|
|
spine-current
|
|
spine-parent
|
|
with-spine
|
|
checksum-block)
|
|
|
|
(import (chezscheme)
|
|
(crc32c checksum)
|
|
(fmt fmt)
|
|
(srfi s8 receive)
|
|
(utils))
|
|
|
|
(define __ (load-shared-object "./bcache/bcache.so"))
|
|
|
|
(define bcache-simple
|
|
(foreign-procedure "bcache_simple" (string unsigned) ptr))
|
|
|
|
(define bcache-destroy
|
|
(foreign-procedure "bcache_destroy" (ptr) void))
|
|
|
|
(define-syntax with-bcache
|
|
(syntax-rules ()
|
|
((_ (name path nr-cache-blocks) b1 b2 ...)
|
|
(let ((name (bcache-simple path nr-cache-blocks)))
|
|
(dynamic-wind
|
|
(lambda () #f)
|
|
(lambda () b1 b2 ...)
|
|
(lambda () (bcache-destroy name)))))))
|
|
|
|
(define get-nr-blocks
|
|
(foreign-procedure "get_nr_blocks" (ptr) unsigned-64))
|
|
|
|
(define get-nr-locked
|
|
(foreign-procedure "get_nr_locked" (ptr) unsigned-64))
|
|
|
|
(define-enumeration get-flag-element
|
|
(zero dirty barrier) get-flags)
|
|
|
|
(define (build-flags es)
|
|
(define (to-bits e)
|
|
(case e
|
|
((zero) 1)
|
|
((dirty) 2)
|
|
((barrier) 4)))
|
|
|
|
(define (combine fs e)
|
|
(fxior fs (to-bits e)))
|
|
|
|
(fold-left combine 0 (enum-set->list es)))
|
|
|
|
(define (fail msg)
|
|
(raise
|
|
(condition
|
|
(make-error)
|
|
(make-message-condition msg))))
|
|
|
|
(define-ftype Block
|
|
(struct
|
|
(data void*)
|
|
(index unsigned-64)))
|
|
|
|
(define (block-data b)
|
|
(ftype-ref Block (data) b))
|
|
|
|
(define (block-index b)
|
|
(ftype-ref Block (index) b))
|
|
|
|
(define (get-block cache index flags)
|
|
(define getb (foreign-procedure "get_block" (ptr unsigned-64 unsigned) (* Block)))
|
|
|
|
(let ((b (getb cache index (build-flags flags))))
|
|
(if (ftype-pointer-null? b)
|
|
(fail (fmt #f "unable to get block " index))
|
|
b)))
|
|
|
|
(define release-block
|
|
(foreign-procedure "release_block" ((* Block)) void))
|
|
|
|
(define (flush-cache cache)
|
|
(define flush (foreign-procedure "flush_cache" (ptr) int))
|
|
|
|
(let ((r (flush cache)))
|
|
(when (< 0 r)
|
|
(fail "flush_cache failed"))))
|
|
|
|
(define prefetch-block
|
|
(foreign-procedure "prefetch_block" (ptr unsigned-64) void))
|
|
|
|
(define-syntax with-block
|
|
(syntax-rules ()
|
|
((_ (b cache index flags) b1 b2 ...)
|
|
(let ((b (get-block cache index flags)))
|
|
(dynamic-wind
|
|
(lambda () #f)
|
|
(lambda () b1 b2 ...)
|
|
(lambda () (release-block b)))))))
|
|
|
|
;;;--------------------------------------------------------
|
|
;;; Spine
|
|
;;;--------------------------------------------------------
|
|
(define-record-type spine
|
|
(fields (immutable cache) (mutable max) (mutable entries))
|
|
(protocol
|
|
(lambda (new)
|
|
(lambda (cache max)
|
|
(new cache max '())))))
|
|
|
|
(define (spine-exit sp)
|
|
(for-each release-block (spine-entries sp)))
|
|
|
|
(define (pop-last xs)
|
|
(let ((rs (reverse xs)))
|
|
(values (car xs) (reverse (cdr xs)))))
|
|
|
|
(define (spine-step% sp index flags)
|
|
(let ((b (get-block (spine-cache sp) index flags)))
|
|
(if (> (length (spine-entries sp))
|
|
(spine-max sp))
|
|
(receive (oldest-b es) (pop-last (spine-entries sp))
|
|
(release-block oldest-b)
|
|
(spine-entries-set! sp (cons b es)))
|
|
(spine-entries-set! sp (cons b (spine-entries sp))))))
|
|
|
|
(define (spine-current sp)
|
|
(car (spine-entries sp)))
|
|
|
|
(define (spine-parent sp)
|
|
(cadr (spine-entries sp)))
|
|
|
|
(define-syntax with-spine
|
|
(syntax-rules ()
|
|
((_ (sp cache max) b1 b2 ...)
|
|
(let ((sp (make-spine cache max)))
|
|
(dynamic-wind
|
|
(lambda () #f)
|
|
(lambda () b1 b2 ...)
|
|
(lambda () (spine-exit sp)))))))
|
|
|
|
(define-syntax spine-step
|
|
(syntax-rules ()
|
|
((_ sp (b index flags) b1 b2 ...)
|
|
(begin
|
|
(spine-step% sp index flags)
|
|
(let ((b (spine-current sp)))
|
|
b1 b2 ...)))))
|
|
|
|
;;;--------------------------------------------------------
|
|
;;; Checksumming
|
|
;;;--------------------------------------------------------
|
|
(define md-block-size 4096)
|
|
|
|
(define (checksum-block b offset salt)
|
|
(let ((ptr (make-ftype-pointer unsigned-8
|
|
(+ (block-data b) offset))))
|
|
(bitwise-xor salt (crc32c #xffffffff ptr (- md-block-size offset)))))
|
|
)
|