From 01539b3b7285c66d1798e838bbd3b40255487e33 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Piotr=20Ma=C5=9Blanka?= <piotr.maslanka@henrietta.com.pl>
Date: Sat, 28 Nov 2020 21:02:32 +0100
Subject: [PATCH] use mmap for writes too

---
 docs/chunks.rst    |  8 ++++++++
 docs/index.rst     |  3 ++-
 docs/usage.rst     |  1 -
 tempsdb/chunks.pxd |  1 +
 tempsdb/chunks.pyx | 20 ++++++++++++--------
 5 files changed, 23 insertions(+), 10 deletions(-)
 create mode 100644 docs/chunks.rst

diff --git a/docs/chunks.rst b/docs/chunks.rst
new file mode 100644
index 0000000..cdf78eb
--- /dev/null
+++ b/docs/chunks.rst
@@ -0,0 +1,8 @@
+Chunk
+=====
+
+For your convenience the class :class:`~tempsdb.chunks.Chunk` was also documented, but don't use
+it directly:
+
+.. autoclass:: tempsdb.chunks.Chunk
+    :members:
diff --git a/docs/index.rst b/docs/index.rst
index 0f61f69..d4621d4 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -12,8 +12,9 @@ Welcome to tempsdb's documentation!
 
    usage
    exceptions
+   chunks
 
-It tries to use mmap for reads where possible, and in general be as zero-copy as possible (ie. the
+It tries to use mmap for reads and writes, and in general is as zero-copy as possible (ie. the
 only time data is unserialized is when a particular entry is read).
 
 Stored time series with a 8-bit timestamp and a fixed length of data.
diff --git a/docs/usage.rst b/docs/usage.rst
index 3daca86..fdc9540 100644
--- a/docs/usage.rst
+++ b/docs/usage.rst
@@ -14,4 +14,3 @@ Then you can create and retrieve particular series:
 
 .. autoclass:: tempsdb.series.TimeSeries
     :members:
-
diff --git a/tempsdb/chunks.pxd b/tempsdb/chunks.pxd
index 94aac24..d5a1eaf 100644
--- a/tempsdb/chunks.pxd
+++ b/tempsdb/chunks.pxd
@@ -18,6 +18,7 @@ cdef class Chunk:
     cpdef void close(self)
     cpdef tuple get_piece_at(self, unsigned int index)
     cpdef int put(self, unsigned long long timestamp, bytes data) except -1
+    cpdef int sync(self) except -1
     cdef inline int length(self):
         return self.entries
 
diff --git a/tempsdb/chunks.pyx b/tempsdb/chunks.pyx
index 275d11a..0514bdb 100644
--- a/tempsdb/chunks.pyx
+++ b/tempsdb/chunks.pyx
@@ -56,6 +56,13 @@ cdef class Chunk:
         self.max_ts, = STRUCT_Q.unpack(self.mmap[-TIMESTAMP_SIZE-self.block_size:-self.block_size])
         self.min_ts, = STRUCT_Q.unpack(self.mmap[HEADER_SIZE:HEADER_SIZE+TIMESTAMP_SIZE])
 
+    cpdef int sync(self) except -1:
+        """
+        Synchronize the mmap
+        """
+        self.mmap.flush()
+        return 0
+
     cpdef int put(self, unsigned long long timestamp, bytes data) except -1:
         """
         Append a record to this chunk
@@ -73,14 +80,11 @@ cdef class Chunk:
             raise ValueError('data not equal in length to block size!')
         if timestamp <= self.max_ts:
             raise ValueError('invalid timestamp')
-
-        cdef bytearray data_to_write = bytearray(TIMESTAMP_SIZE+self.block_size)
-        data_to_write[0:TIMESTAMP_SIZE] = STRUCT_Q.pack(timestamp)
-        data_to_write[TIMESTAMP_SIZE:] = data
+        cdef unsigned long long pointer_at_end = (self.entries+1)*(TIMESTAMP_SIZE+self.block_size) + HEADER_SIZE
         with self.write_lock:
-            self.file.seek(0, 2)
-            self.file.write(data_to_write)
-            self.mmap.resize((self.entries+1)*(8+self.block_size)+HEADER_SIZE)
+            self.mmap.resize(pointer_at_end)
+            self.mmap[pointer_at_end-self.block_size-TIMESTAMP_SIZE:pointer_at_end-self.block_size] = STRUCT_Q.pack(timestamp)
+            self.mmap[pointer_at_end-self.block_size:pointer_at_end] = data
             self.entries += 1
             self.max_ts = timestamp
         return 0
@@ -104,7 +108,7 @@ cdef class Chunk:
             yield self.get_piece_at(i)
 
     def __iter__(self) -> tp.Iterator[tp.Tuple[int, bytes]]:
-        cdef unsigned long i = 0
+        cdef int i
         for i in range(self.entries):
             yield self.get_piece_at(i)
 
-- 
GitLab