oscarmlage oscarmlage

ZODB, how to properly delete a BLOB file

Written by oscarmlage on

Due one of my Pyramid current projects, I was playing a bit with ZODB and blob image storing. After reading here and there, I had no idea how to properly delete a filesystem stored image, blob field related. I though best way was to use remove_committed() ZODB.blob method with something like:

def delete_avatar():
    image = myobj.avatar
    if isinstance(image, Blob):
        remove_committed(image.committed())
        myobj.avatar = None

But after talking a bit with skilled ZODB people, they said that updating the database value and packing the database was enough to clear all the references in filesystem. First time ever I read something about "packing" a ZODB, so I had to probe it by myself.

pshell$ profile.avatar
(ZODB.blob.Blob object at 0x108167230)

Once we reached the image we can get it's path and some other interesting data for this test from pshell and shell:

pshell$ profile.avatar.committed()
'/path/to/myproject/var/blobstorage/0x00/0x00/0x00/0x00/0x00/0x02/0xbd/0x68/0x03ab15928a1fb511.blob'
$ ls /path/to/myproject/var/blobstorage/0x00/0x00/0x00/0x00/0x00/0x02/0xbd/0x68/0x03ab15928a1fb511.blob
/0x03ab15928a1fb511.blob
$ find . -name *.blob | wc -l
12
$ du -s .
4784	.

Nice!, if I open the .blob file with whatever image editor I get the proper image, next step is to enter in pshell mode again, update the database code to None,commit the transaction and see what's happening in the filesystem:

pshell$ profile.avatar = None
pshell$ profile.avatar
pshell$ import transaction
pshell$ transaction.commit()
$ find . -name *.blob | wc -l
12
$ du -s .
4784	.

Nothing seems to be happened, after the commit, find and du are showing the same information as before, last step is to pack the database...

pshell$ from pyramid_zodbconn import get_connection
pshell$ conn = get_connection(request)
pshell$ conn.db().pack()
$ find . -name *.blob | wc -l
11
$ du -s .
4504	.
$ ls /path/to/myproject/var/blobstorage/0x00/0x00/0x00/0x00/0x00/0x02/0xbd/0x68/0x03ab15928a1fb511.blob
$

That's it!, after a couple of seconds "packing", the filesystem seems to be updated, the file was properly deleted and all the information seems to be in a right state.

In the end seems that the remove_commited() function was not the right way to delete a BLOB file from ZODB, thumbs up for the packing!.