将外部存储器解释为Lisp存储器(反之亦然),而无需复制数据

时间:2018-11-19 20:12:41

标签: common-lisp cffi

我尝试使用数据库API C函数(例如db-write-chunk)将BLOB逐块写入数据库。 此函数将指向外部存储器(放置块)的指针作为参数。 因此,我为块创建了缓冲区:foreign-buffer。 我将read-sequence从文件(或二进制流)中获取大块数据到stream-buffer中:

(let ((foreign-buffer (foreign-alloc :uchar 1024)))
      (stream-buffer ((make-array 1024 :element-type '(unsigned-byte 8))))
    (loop
        for cnt = (read-sequence stream-buffer MY-STREAM)
        while (> cnt 0)
        do
          ;; copy cnt bytes from stream-buffer into foreign-buffer 
          ;; call db-write-chunk with foreign-buffer
BLOB中的

L适用于Large,循环可能会迭代多次。 除此之外,所有这些代码都可以由外部循环包装(例如,批量插入)。 因此,我想减少循环主体中的步骤数。

要完成此操作,我需要:

  • 能够将序列读取到流缓冲区中,而不是直接读取到外部缓冲区中,如下所示:

    (read-sequence (coerce foreign-buffer '(vector/array ...)) MY-STREAM)
    
  • ,或者能够将流缓冲区解释为外部内存,如下所示:

    (db-write-chunk (mem-aptr stream-buffer :uchar 0))
    

是否可以仅使用单个缓冲区(本机缓冲区或外部缓冲区)解决我的问题,而无需在它们之间复制内存?

1 个答案:

答案 0 :(得分:0)

与其他任何ffi一样,这取决于实现,但是cffi具有cffi:make-shareable-byte-vector,它是一个CL (unsigned-byte 8)数组,然后可以与cffi:with-pointer-to-vector-data一起使用:

(cffi:defcfun memset :pointer
  (ptr :pointer)
  (val :int)
  (size :int))

(let ((vec (cffi:make-shareable-byte-vector 256)))
  (cffi:with-pointer-to-vector-data (ptr vec)
    (memset ptr 0 (length vec))))

根据您的使用情况,它可能比static-vectors更可取,因为您不必记住手动释放它。在SBCL上,这可以通过在with-pointer-to-vector-data期间固定矢量数据来实现。