Skip to content

Commit df9f055

Browse files
committed
optimize DbSession.get_blob_chunks to return read-only row objects
avoiding creating lots of orm objects
1 parent 09b8e71 commit df9f055

5 files changed

Lines changed: 54 additions & 13 deletions

File tree

prime_backup/action/helpers/chunk_grouper.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import dataclasses
22
import logging
33
import time
4-
from typing import Dict, List, Optional
4+
from typing import Dict, List, Optional, Union
55

66
from prime_backup.action.helpers.create_backup_utils import CreateBackupTimeCostKey
77
from prime_backup.constants import chunk_constants
88
from prime_backup.db import schema
99
from prime_backup.db.session import DbSession
10+
from prime_backup.db.values import ChunkRow
1011
from prime_backup.utils import chunk_utils
1112
from prime_backup.utils.time_cost_stats import TimeCostStats
1213

@@ -22,7 +23,7 @@ class ChunkLike:
2223
stored_size: int
2324

2425
@classmethod
25-
def of(cls, chunk: schema.Chunk) -> 'ChunkGrouper.ChunkLike':
26+
def of(cls, chunk: Union[schema.Chunk, ChunkRow]) -> 'ChunkGrouper.ChunkLike':
2627
return cls(
2728
id=chunk.id,
2829
hash=chunk.hash,

prime_backup/action/migrate_hash_method_action.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from prime_backup.db import schema
1414
from prime_backup.db.access import DbAccess
1515
from prime_backup.db.session import DbSession
16-
from prime_backup.db.values import BlobStorageMethod
16+
from prime_backup.db.values import BlobStorageMethod, ChunkRow
1717
from prime_backup.exceptions import PrimeBackupError
1818
from prime_backup.types.chunk_info import ChunkInfo
1919
from prime_backup.types.hash_method import HashMethod
@@ -183,7 +183,7 @@ def __regroup_chunked_blobs(self, session: DbSession):
183183
# Step 1 - collect blob -> ordered chunks before destroying the binding chain
184184
chunked_blobs = session.list_blobs_by_storage_method(BlobStorageMethod.chunked)
185185
total = len(chunked_blobs)
186-
blob_chunks_map: Dict[int, Dict[int, schema.Chunk]] = {}
186+
blob_chunks_map: Dict[int, Dict[int, ChunkRow]] = {}
187187
for blob in chunked_blobs:
188188
offset_chunks = session.get_blob_chunks(blob.id) # sorted by absolute_offset
189189
blob_chunks_map[blob.id] = {oc.offset: oc.chunk for oc in offset_chunks}

prime_backup/db/session.py

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
from prime_backup.db import schema, db_constants
1515
from prime_backup.db.db_features import DbFeatures
16-
from prime_backup.db.values import FileRole, BackupTagDict, OffsetChunk, OffsetChunkGroup, BlobStorageMethod, ChunkGroupChunkBindingIdentifier, BlobChunkGroupBindingIdentifier, FileIdentifier
16+
from prime_backup.db.values import FileRole, BackupTagDict, ChunkRow, OffsetChunk, OffsetChunkRow, OffsetChunkGroup, BlobStorageMethod, ChunkGroupChunkBindingIdentifier, BlobChunkGroupBindingIdentifier, FileIdentifier
1717
from prime_backup.exceptions import BackupNotFound, BackupFileNotFound, BlobHashNotFound, PrimeBackupError, FilesetNotFound, FilesetFileNotFound, BlobIdNotFound, ChunkHashNotFound, ChunkIdNotFound, ChunkGroupChunkBindingNotFound, BlobChunkGroupBindingNotFound, ChunkGroupIdNotFound, ChunkGroupHashNotFound, PackIdNotFound
1818
from prime_backup.types.backup_filter import BackupFilter, BackupTagFilter, BackupSortOrder
1919
from prime_backup.types.pack_info import PackEntryInfo
@@ -1097,15 +1097,21 @@ def get_blob_chunk_count(self, blob_id: int) -> int:
10971097
where(schema.BlobChunkGroupBinding.blob_id == blob_id)
10981098
).scalar_one())
10991099

1100-
def get_blob_chunks(self, blob_id: int, *, limit: Optional[int] = None) -> List[OffsetChunk]:
1100+
def get_blob_chunks(self, blob_id: int, *, limit: Optional[int] = None) -> List[OffsetChunkRow]:
11011101
"""
11021102
result is sorted
11031103
"""
11041104
absolute_offset = (schema.BlobChunkGroupBinding.chunk_group_offset + schema.ChunkGroupChunkBinding.chunk_offset).label('absolute_offset')
11051105
stmt = (
11061106
select(
11071107
absolute_offset,
1108-
schema.Chunk
1108+
schema.Chunk.id,
1109+
schema.Chunk.hash,
1110+
schema.Chunk.compress,
1111+
schema.Chunk.raw_size,
1112+
schema.Chunk.stored_size,
1113+
schema.Chunk.pack_id,
1114+
schema.Chunk.pack_offset,
11091115
).
11101116
select_from(schema.BlobChunkGroupBinding).
11111117
join(
@@ -1121,8 +1127,22 @@ def get_blob_chunks(self, blob_id: int, *, limit: Optional[int] = None) -> List[
11211127
)
11221128
if limit is not None:
11231129
stmt = stmt.limit(limit)
1124-
result: Sequence[Row[Tuple[int, schema.Chunk]]] = self.session.execute(stmt).all()
1125-
return [OffsetChunk(offset, chunk) for offset, chunk in result]
1130+
result: Sequence[Row[Tuple[int, int, str, str, int, int, int, int]]] = self.session.execute(stmt).all()
1131+
return [
1132+
OffsetChunkRow(
1133+
offset=offset,
1134+
chunk=ChunkRow(
1135+
id=chunk_id,
1136+
hash=chunk_hash,
1137+
compress=compress,
1138+
raw_size=raw_size,
1139+
stored_size=stored_size,
1140+
pack_id=pack_id,
1141+
pack_offset=pack_offset,
1142+
),
1143+
)
1144+
for offset, chunk_id, chunk_hash, compress, raw_size, stored_size, pack_id, pack_offset in result
1145+
]
11261146

11271147
def batch_get_blob_pretty_chunks(self, blob_ids: List[int]) -> Dict[int, List['PrettyChunk']]:
11281148
"""

prime_backup/db/values.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,26 @@ class BlobStorageMethod(enum.IntEnum):
1414
chunked = 2 # split into chunks and stored as pack entries
1515

1616

17+
@dataclasses.dataclass(frozen=True)
18+
class ChunkRow:
19+
id: int
20+
hash: str
21+
compress: str
22+
raw_size: int
23+
stored_size: int
24+
pack_id: int
25+
pack_offset: int
26+
27+
28+
@dataclasses.dataclass(frozen=True)
29+
class OffsetChunkRow:
30+
offset: int
31+
chunk: ChunkRow
32+
33+
def __lt__(self, other: 'OffsetChunkRow'):
34+
return self.offset < other.offset
35+
36+
1737
@dataclasses.dataclass(frozen=True)
1838
class OffsetChunk:
1939
offset: int

prime_backup/types/chunk_info.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import dataclasses
22
from pathlib import Path
3-
from typing import Iterable, TYPE_CHECKING
3+
from typing import Iterable, TYPE_CHECKING, Union
44

55
from typing_extensions import Self
66

77
from prime_backup.compressors import CompressMethod
88
from prime_backup.db import schema
9-
from prime_backup.db.values import OffsetChunk
9+
from prime_backup.db.values import ChunkRow, OffsetChunk, OffsetChunkRow
1010
from prime_backup.types.pack_info import PackEntryLocation
1111
from prime_backup.utils import misc_utils
1212

@@ -24,7 +24,7 @@ class ChunkInfo:
2424
pack_entry: PackEntryLocation
2525

2626
@classmethod
27-
def of(cls, chunk: schema.Chunk) -> 'ChunkInfo':
27+
def of(cls, chunk: Union[schema.Chunk, ChunkRow]) -> 'ChunkInfo':
2828
return ChunkInfo(
2929
id=chunk.id,
3030
hash=chunk.hash,
@@ -50,7 +50,7 @@ def size(self) -> int:
5050
return self.chunk.raw_size
5151

5252
@classmethod
53-
def of(cls, offset_chunk: OffsetChunk) -> 'OffsetChunkInfo':
53+
def of(cls, offset_chunk: Union[OffsetChunk, OffsetChunkRow]) -> 'OffsetChunkInfo':
5454
return cls(offset_chunk.offset, ChunkInfo.of(offset_chunk.chunk))
5555

5656
def __lt__(self, other: 'OffsetChunkInfo') -> bool:

0 commit comments

Comments
 (0)