Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Basic implementation of backup media store #2538

Merged
merged 29 commits into from
Oct 13, 2017
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
bf4fb1f
Basic implementation of backup media store
erikjohnston Oct 12, 2017
67cb89f
Fix typo
erikjohnston Oct 12, 2017
c8eeef6
Fix typos
erikjohnston Oct 12, 2017
6dfde6d
Remove dead code
erikjohnston Oct 12, 2017
b77a138
Typo
erikjohnston Oct 12, 2017
e283b55
Copy everything to backup
erikjohnston Oct 12, 2017
802ca12
Don't close file prematurely
erikjohnston Oct 12, 2017
1259a76
Get len before close
erikjohnston Oct 12, 2017
cc505b4
getvalue closes buffer
erikjohnston Oct 12, 2017
4ae85ae
Don't close prematurely..
erikjohnston Oct 12, 2017
d76621a
Fix comments
erikjohnston Oct 12, 2017
b60859d
Use make_deferred_yieldable
erikjohnston Oct 13, 2017
64db043
Move makedirs to thread
erikjohnston Oct 13, 2017
3533229
Fix up comments
erikjohnston Oct 13, 2017
e3428d2
Fix typo
erikjohnston Oct 13, 2017
5053714
Fix up thumbnailing function
erikjohnston Oct 13, 2017
0e28281
Fix up
erikjohnston Oct 13, 2017
9732ec6
s/write_to_file/write_to_file_and_backup/
erikjohnston Oct 13, 2017
ae5d186
Make things be absolute paths again
erikjohnston Oct 13, 2017
4d7e1dd
Remove unnecessary diff
erikjohnston Oct 13, 2017
a675bd0
Add paths back in...
erikjohnston Oct 13, 2017
1f43d22
Don't needlessly rename variable
erikjohnston Oct 13, 2017
c021c39
Remove spurious addition
erikjohnston Oct 13, 2017
ad1911b
Comment
erikjohnston Oct 13, 2017
31aa7bd
Move type into key
erikjohnston Oct 13, 2017
b92a8e6
PEP8
erikjohnston Oct 13, 2017
2b24416
Don't reuse source but instead copy from primary media store to backup
erikjohnston Oct 13, 2017
6b725cf
Remove old comment
erikjohnston Oct 13, 2017
1b6b0b1
Add try/finally block to close t_byte_source
erikjohnston Oct 13, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions synapse/config/repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,19 @@ def read_config(self, config):
self.max_upload_size = self.parse_size(config["max_upload_size"])
self.max_image_pixels = self.parse_size(config["max_image_pixels"])
self.max_spider_size = self.parse_size(config["max_spider_size"])

self.media_store_path = self.ensure_directory(config["media_store_path"])

self.backup_media_store_path = config.get("backup_media_store_path")
if self.backup_media_store_path:
self.backup_media_store_path = self.ensure_directory(
self.backup_media_store_path
)

self.synchronous_backup_media_store = config.get(
"synchronous_backup_media_store", False
)

self.uploads_path = self.ensure_directory(config["uploads_path"])
self.dynamic_thumbnails = config["dynamic_thumbnails"]
self.thumbnail_requirements = parse_thumbnail_requirements(
Expand Down Expand Up @@ -115,6 +127,14 @@ def default_config(self, **kwargs):
# Directory where uploaded images and attachments are stored.
media_store_path: "%(media_store)s"

# A secondary directory where uploaded images and attachments are
# stored as a backup.
# backup_media_store_path: "%(media_store)s"

# Whether to wait for successful write to backup media store before
# returning successfully.
# synchronous_backup_media_store: false

# Directory where in-progress uploads are stored.
uploads_path: "%(uploads_path)s"

Expand Down
77 changes: 55 additions & 22 deletions synapse/rest/media/v1/filepath.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,80 +15,111 @@

import os
import re
import functools

NEW_FORMAT_ID_RE = re.compile(r"^\d\d\d\d-\d\d-\d\d")


def _wrap_in_base_path(func):
"""Takes a function that returns a relative path and turns it into an
absolute path based on the location of the primary media store
"""
@functools.wraps(func)
def _wrapped(self, *args, **kwargs):
path = func(self, *args, **kwargs)
return os.path.join(self.base_path, path)

return _wrapped


class MediaFilePaths(object):
"""Describes where files are stored on disk.

Most of the functions have a `*_rel` variant which returns a file path that
is relative to the base media store path. This is mainly used when we want
to write to the backup media store (when one is configured)
"""

def __init__(self, base_path):
self.base_path = base_path
def __init__(self, primary_base_path):
self.base_path = primary_base_path

def default_thumbnail(self, default_top_level, default_sub_type, width,
height, content_type, method):
def default_thumbnail_rel(self, default_top_level, default_sub_type, width,
height, content_type, method):
top_level_type, sub_type = content_type.split("/")
file_name = "%i-%i-%s-%s-%s" % (
width, height, top_level_type, sub_type, method
)
return os.path.join(
self.base_path, "default_thumbnails", default_top_level,
"default_thumbnails", default_top_level,
default_sub_type, file_name
)

def local_media_filepath(self, media_id):
default_thumbnail = _wrap_in_base_path(default_thumbnail_rel)

def local_media_filepath_rel(self, media_id):
return os.path.join(
self.base_path, "local_content",
"local_content",
media_id[0:2], media_id[2:4], media_id[4:]
)

def local_media_thumbnail(self, media_id, width, height, content_type,
method):
local_media_filepath = _wrap_in_base_path(local_media_filepath_rel)

def local_media_thumbnail_rel(self, media_id, width, height, content_type,
method):
top_level_type, sub_type = content_type.split("/")
file_name = "%i-%i-%s-%s-%s" % (
width, height, top_level_type, sub_type, method
)
return os.path.join(
self.base_path, "local_thumbnails",
"local_thumbnails",
media_id[0:2], media_id[2:4], media_id[4:],
file_name
)

def remote_media_filepath(self, server_name, file_id):
local_media_thumbnail = _wrap_in_base_path(local_media_thumbnail_rel)

def remote_media_filepath_rel(self, server_name, file_id):
return os.path.join(
self.base_path, "remote_content", server_name,
"remote_content", server_name,
file_id[0:2], file_id[2:4], file_id[4:]
)

def remote_media_thumbnail(self, server_name, file_id, width, height,
content_type, method):
remote_media_filepath = _wrap_in_base_path(remote_media_filepath_rel)

def remote_media_thumbnail_rel(self, server_name, file_id, width, height,
content_type, method):
top_level_type, sub_type = content_type.split("/")
file_name = "%i-%i-%s-%s" % (width, height, top_level_type, sub_type)
return os.path.join(
self.base_path, "remote_thumbnail", server_name,
"remote_thumbnail", server_name,
file_id[0:2], file_id[2:4], file_id[4:],
file_name
)

remote_media_thumbnail = _wrap_in_base_path(remote_media_thumbnail_rel)

def remote_media_thumbnail_dir(self, server_name, file_id):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this get a _rel for consistency?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This actually returns absolute paths (now..)

return os.path.join(
self.base_path, "remote_thumbnail", server_name,
file_id[0:2], file_id[2:4], file_id[4:],
)

def url_cache_filepath(self, media_id):
def url_cache_filepath_rel(self, media_id):
if NEW_FORMAT_ID_RE.match(media_id):
# Media id is of the form <DATE><RANDOM_STRING>
# E.g.: 2017-09-28-fsdRDt24DS234dsf
return os.path.join(
self.base_path, "url_cache",
"url_cache",
media_id[:10], media_id[11:]
)
else:
return os.path.join(
self.base_path, "url_cache",
"url_cache",
media_id[0:2], media_id[2:4], media_id[4:],
)

url_cache_filepath = _wrap_in_base_path(url_cache_filepath_rel)

def url_cache_filepath_dirs_to_delete(self, media_id):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_rel? or at least clarify it in the comments?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This actually returns absolute paths (now..)

"The dirs to try and remove if we delete the media_id file"
if NEW_FORMAT_ID_RE.match(media_id):
Expand All @@ -110,8 +141,8 @@ def url_cache_filepath_dirs_to_delete(self, media_id):
),
]

def url_cache_thumbnail(self, media_id, width, height, content_type,
method):
def url_cache_thumbnail_rel(self, media_id, width, height, content_type,
method):
# Media id is of the form <DATE><RANDOM_STRING>
# E.g.: 2017-09-28-fsdRDt24DS234dsf

Expand All @@ -122,17 +153,19 @@ def url_cache_thumbnail(self, media_id, width, height, content_type,

if NEW_FORMAT_ID_RE.match(media_id):
return os.path.join(
self.base_path, "url_cache_thumbnails",
"url_cache_thumbnails",
media_id[:10], media_id[11:],
file_name
)
else:
return os.path.join(
self.base_path, "url_cache_thumbnails",
"url_cache_thumbnails",
media_id[0:2], media_id[2:4], media_id[4:],
file_name
)

url_cache_thumbnail = _wrap_in_base_path(url_cache_thumbnail_rel)

def url_cache_thumbnail_directory(self, media_id):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_rel?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This actually returns absolute paths (now..)

# Media id is of the form <DATE><RANDOM_STRING>
# E.g.: 2017-09-28-fsdRDt24DS234dsf
Expand Down
Loading