Skip to content

Instantly share code, notes, and snippets.

@smurfix
Created May 8, 2014 14:17
Show Gist options
  • Save smurfix/827026360f7ee3245b86 to your computer and use it in GitHub Desktop.
Save smurfix/827026360f7ee3245b86 to your computer and use it in GitHub Desktop.
class BinData(ObjectRef):
"""
Stores (a reference to) one data file
This object implements a content-based file system: the hash of the
file contents is an index.
"""
storage_seq = Column(Integer, autoincrement=True, unique=True)
mime_id = Column(Integer, ForeignKey(MIMEtype.id), nullable=False, index=True)
mime = relationship(MIMEtype, primaryjoin=mime_id==MIMEtype.id)
name = Column(Unicode(100), nullable=False)
hash = Column(Unicode(33), nullable=True, unique=True) ## NULL if deleted, 404's without hitting the file system
timestamp = Column(DateTime,default=datetime.utcnow)
size = Column(Integer)
[…]
def _get_chars(self):
"""This creates a unique path+filename for storage."""
if self.storage_seq is None:
db.flush()
db.refresh(self,('storage_seq',))
if self.storage_seq is None: ## sqlite, probably
from sqlalchemy import func
self.storage_seq = (db.query(func.max(BinData.storage_seq)).scalar() or 0) +1
db.flush()
assert self.storage_seq, repr(self)
id = self.storage_seq-1
chars = "abcdefghjk" ## 100 files per end directory (long names)
midchars = "abcdefghjkmnopqr" ## 256 subdirectories (short names)
fc = []
flast = chars[id % len(chars)]
id = id // len(chars)
flast += chars[id % len(chars)]
id = id // len(chars)
while id:
id -= 1
c = midchars[id % len(midchars)]
id = id // len(midchars)
c = midchars[id % len(midchars)] + c
id = id // len(midchars)
fc.insert(0,c)
fc.append("_")
fc.append(self.name+"_"+self.hash[0:10]+flast)
if self.mime.ext:
fc[-1] += "."+self.mime.ext
return fc
try:
from hashlib import sha1
except ImportError:
from sha import sha as sha1
def hash_data(content):
"""
Create an URL-compatible ASCII hash
"""
from base64 import b64encode
return b64encode(sha1(content).digest(),altchars=str("-_")).rstrip("=")
## The mysql driver ignores autoincrement on non-primary-key columns.
## Workaround:
from sqlalchemy import event
from sqlalchemy.schema import DDL
event.listen(BinData.__table__, 'after_create',
DDL("ALTER TABLE bindata CHANGE storage_seq storage_seq INT AUTO_INCREMENT NOT NULL", on="mysql"))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment