Go for it!

モーターサイクルと自転車とキャンプの日々。

GAE Datastoreの制限と回避方法

先日のブログエントリに書きましたが、GAE Uploaderをいじっていて制限にぶち当たりました。

  • アップロードは10MBまで
  • Datastoreのレコードは1MBまで

アップロードしたファイルをDatastoreに保存しようとすると、

アップロード可能サイズ > 保存可能サイズ

なので、そのまま保存することが出来ません。

対策として、アップロードファイルをchunkに分割してDatastoreに並び順付きで保存すればいいらしい。で、実際にコードを書いてみたら動いたので、オリジナルのGAE Uploaderからの差分を公開。

[code lang=“python”] — main.py-orig 2009-04-04 18:59:58.000000000 +0900 +++ main.py 2009-04-04 20:46:38.000000000 +0900 @@ -16,6 +16,7 @@ comment = db.StringProperty() size = db.IntegerProperty() author = db.UserProperty() + split = db.IntegerProperty(0) created_at = db.DateTimeProperty(auto_now_add=True)

 def delete(self):

@@ -27,6 +28,7 @@ class FileBin(db.Model): userfile = db.ReferenceProperty(UserFile) bin = db.BlobProperty() + sortorder = db.IntegerProperty()

class MainPage(webapp.RequestHandler): def get(self): @@ -50,14 +52,21 @@ if not userfile: self.error(404) return self.response.out.write(‘404 not found’) - bin = userfile.filebin_set.get() if isinstance(self.request.get(‘dl’), unicode): self.response.headers[‘Content-Type’] = ‘application/octet-stream’ content_disposition = ‘attachment; filename=“%s”’ % str(userfile.name) # header values must be string. self.response.headers[‘Content-Disposition’] = content_disposition else: - self.response.headers[‘Content-Type’] = str(userfile.mime) - self.response.out.write(bin.bin) + self.response.headers[‘Content-Type’] = str(userfile.mime) + + if userfile.split == 1: + results = userfile.filebin_set.order(‘sortorder’).fetch(10) +
+ for result in results: + self.response.out.write(result.bin) + else: + bin = userfile.filebin_set.get() + self.response.out.write(bin.bin)

class Upload(webapp.RequestHandler): def post(self): @@ -71,9 +80,22 @@ userfile.comment = self.request.get(“comment”) bin = db.Blob(file_data) userfile.size = len(bin) + if len(bin) > 1000000: + userfile.split=1 + userfile.put() - filebin = FileBin(userfile=userfile, bin=bin) - filebin.put() + + if len(file_data) > 1000000: + for i in range(0, 9): + chunk = file_data[i1000000:i1000000+1000000] + filebin=FileBin(userfile=userfile, bin=chunk, sortorder=i) + filebin.put() + if len(chunk) < 1000000: + break + else: + filebin = FileBin(userfile=userfile, bin=bin) + filebin.put() + # delete oldest file if UserFile.all().count() > FILE_MAX: oldest_file = UserFile.all().order(‘created_at’).get() [/code] ※マジックナンバーが埋まってるのはご愛敬で

とりあえず正常に動いているみたい?

pythonはまだまだ駆け出しでよく解らないところがある。 例えば、

  • substr()ってないの?
  • Blob objectってどうやって連結するの?(stringみたいに+したら駄目でした)

などなど。

GAE Uploaderは自分のレベルにマッチした良い教材でした。公開してくださったid:ikasamaHさんに感謝。

[ad#text_wide]