Commit 6773fda0 authored by Kirill Smelkov's avatar Kirill Smelkov

bigfile/zodb: Don't write ZBlk to DB if it was not changed

For ZBlk1 we already compare ZData content about whether it was changed
compared to data already stored to DB, and do not store it twice if data
is the same.

However ZBlk itself is always marked as changed, if corresponding memory
page was dirtied. This results in transactions like

Trans #33915309 tid=03b6944919befeee time=2016-04-17 22:01:06.034237 offset=140320105842
    status=' ' user='...' description='...'
  # ... other parts, but no ZData here
  data #00002 oid=000000000026fc4c size=79 class=wendelin.bigfile.file_zodb.ZBlk1

where ZBlk1 is committed the same without necessity.

NOTE we cannot avoid committing ZBlk in all cases, because it is used to signal
    other DB clients that a ZBlk needs to be invalidated and this way associated
    fileh pages are invalidated too.

    This cannot work via ZData, because ZData don't have back-pointer to
    ZBlk1 or to corresponding zfile.
parent 2ce96a76
...@@ -113,6 +113,12 @@ class ZBlkBase(Persistent): ...@@ -113,6 +113,12 @@ class ZBlkBase(Persistent):
# client requests us to set blkdata to be later saved to DB # client requests us to set blkdata to be later saved to DB
# (DB <- ) .blkdata <- memory-page # (DB <- ) .blkdata <- memory-page
#
# return: blkchanged=(True|False) - whether blk should be considered changed
# after setting its data.
#
# False - when we know the data set was the same
# True - data was not the same or we don't know
def setblkdata(self, buf): def setblkdata(self, buf):
raise NotImplementedError() raise NotImplementedError()
...@@ -182,6 +188,10 @@ class ZBlk0(ZBlkBase): ...@@ -182,6 +188,10 @@ class ZBlk0(ZBlkBase):
# trim trailing \0 # trim trailing \0
self._v_blkdata = blkdata.rstrip(b'\0') # FIXME copy self._v_blkdata = blkdata.rstrip(b'\0') # FIXME copy
# buf always considered to be "changed", as we do not keep old data to
# compare.
return True
# DB (through pickle) requests us to emit state to save # DB (through pickle) requests us to emit state to save
# DB <- ._v_blkdata (<- memory-page) # DB <- ._v_blkdata (<- memory-page)
...@@ -296,6 +306,7 @@ class ZBlk1(ZBlkBase): ...@@ -296,6 +306,7 @@ class ZBlk1(ZBlkBase):
def setblkdata(self, buf): def setblkdata(self, buf):
chunktab = self.chunktab chunktab = self.chunktab
CHUNKSIZE = self.CHUNKSIZE CHUNKSIZE = self.CHUNKSIZE
blkchanged= False
# first make sure chunktab was previously written with the same CHUNKSIZE # first make sure chunktab was previously written with the same CHUNKSIZE
# (for simplicity we don't allow several chunk sizes to mix) # (for simplicity we don't allow several chunk sizes to mix)
...@@ -320,6 +331,7 @@ class ZBlk1(ZBlkBase): ...@@ -320,6 +331,7 @@ class ZBlk1(ZBlkBase):
if chunk is not None: if chunk is not None:
del chunktab[start] del chunktab[start]
chunk._p_deactivate() chunk._p_deactivate()
blkchanged = True
# some !0 data -> compare and store if changed # some !0 data -> compare and store if changed
else: else:
...@@ -328,6 +340,7 @@ class ZBlk1(ZBlkBase): ...@@ -328,6 +340,7 @@ class ZBlk1(ZBlkBase):
if chunk.data != data: if chunk.data != data:
chunk.data = data chunk.data = data
blkchanged = True
# data changed and is queued to be committed to db. # data changed and is queued to be committed to db.
# ZData will care about this chunk deactivation after DB # ZData will care about this chunk deactivation after DB
# asks for its data - see ZData.__getstate__(). # asks for its data - see ZData.__getstate__().
...@@ -337,6 +350,8 @@ class ZBlk1(ZBlkBase): ...@@ -337,6 +350,8 @@ class ZBlk1(ZBlkBase):
# more needed # more needed
chunk._p_deactivate() chunk._p_deactivate()
return blkchanged
# DB (through pickle) requests us to emit state to save # DB (through pickle) requests us to emit state to save
# DB <- .chunktab (<- memory-page) # DB <- .chunktab (<- memory-page)
...@@ -481,7 +496,8 @@ class ZBigFile(LivePersistent): ...@@ -481,7 +496,8 @@ class ZBigFile(LivePersistent):
type(zblk) is not zblk_type_write: type(zblk) is not zblk_type_write:
zblk = self.blktab[blk] = zblk_type_write() zblk = self.blktab[blk] = zblk_type_write()
zblk.setblkdata(buf) blkchanged = zblk.setblkdata(buf)
if blkchanged:
zblk._p_changed = True # if zblk was already in DB: _p_state -> CHANGED zblk._p_changed = True # if zblk was already in DB: _p_state -> CHANGED
zblk.bindzfile(self, blk) zblk.bindzfile(self, blk)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment