Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/file-server/zfs/names.ts
1447 views
1
import { join } from "path";
2
import { context } from "./config";
3
import { primaryKey, type PrimaryKey } from "./types";
4
import { randomId } from "@cocalc/conat/names";
5
6
export function databaseFilename(data: string) {
7
return join(data, "database.sqlite3");
8
}
9
10
export function namespaceDataset({
11
pool,
12
namespace,
13
}: {
14
pool: string;
15
namespace: string;
16
}) {
17
return `${pool}/${namespace}`;
18
}
19
20
// Archives
21
// There is one single dataset for each namespace/pool pair: All the different
22
// archives across filesystems are stored in the *same* dataset, since there is no
23
// point in separating them.
24
export function archivesDataset({
25
pool,
26
namespace,
27
}: {
28
pool: string;
29
namespace: string;
30
}) {
31
return `${namespaceDataset({ pool, namespace })}/archives`;
32
}
33
34
export function archivesMountpoint({
35
pool,
36
namespace,
37
}: {
38
pool: string;
39
namespace: string;
40
}) {
41
return join(context.ARCHIVES, namespace, pool);
42
}
43
44
export function filesystemArchivePath({
45
pool,
46
...fs
47
}: PrimaryKey & { pool: string }) {
48
const pk = primaryKey(fs);
49
return join(
50
archivesMountpoint({ pool, namespace: pk.namespace }),
51
pk.owner_type,
52
pk.owner_id,
53
pk.name,
54
);
55
}
56
57
export function filesystemArchiveFilename(opts: PrimaryKey & { pool: string }) {
58
const { owner_type, owner_id, name } = primaryKey(opts);
59
return join(
60
filesystemArchivePath(opts),
61
`full-${owner_type}-${owner_id}-${name}.zfs`,
62
);
63
}
64
65
export function filesystemStreamsPath(opts: PrimaryKey & { pool: string }) {
66
return join(filesystemArchivePath(opts), "streams");
67
}
68
69
export function filesystemStreamsFilename({
70
snapshot1,
71
snapshot2,
72
...opts
73
}: PrimaryKey & { snapshot1: string; snapshot2: string; pool: string }) {
74
return join(filesystemStreamsPath(opts), `${snapshot1}-${snapshot2}.zfs`);
75
}
76
77
// Bup
78
export function bupDataset({
79
pool,
80
namespace,
81
}: {
82
pool: string;
83
namespace: string;
84
}) {
85
return `${namespaceDataset({ pool, namespace })}/bup`;
86
}
87
88
export function bupMountpoint({
89
pool,
90
namespace,
91
}: {
92
pool: string;
93
namespace: string;
94
}) {
95
return join(context.BUP, namespace, pool);
96
}
97
98
export function bupFilesystemMountpoint({
99
pool,
100
...fs
101
}: PrimaryKey & { pool: string }) {
102
const pk = primaryKey(fs);
103
return join(
104
bupMountpoint({ ...pk, pool }),
105
pk.owner_type,
106
pk.owner_id,
107
pk.name,
108
);
109
}
110
111
// Filesystems
112
113
export function filesystemsPath({ namespace }) {
114
return join(context.FILESYSTEMS, namespace);
115
}
116
117
export function filesystemMountpoint(fs: PrimaryKey) {
118
const pk = primaryKey(fs);
119
return join(filesystemsPath(pk), pk.owner_type, pk.owner_id, pk.name);
120
}
121
122
export function filesystemSnapshotMountpoint(
123
opts: PrimaryKey & { snapshot: string },
124
) {
125
return join(filesystemMountpoint(opts), ".zfs", "snapshot", opts.snapshot);
126
}
127
128
export function filesystemsDataset({
129
pool,
130
namespace,
131
}: {
132
pool: string;
133
namespace: string;
134
}) {
135
return `${namespaceDataset({ pool, namespace })}/filesystems`;
136
}
137
138
// There is one single dataset for each project_id/namespace/pool tripple since it
139
// is critical to separate each project to properly support snapshots, clones,
140
// backups, etc.
141
export function filesystemDataset({
142
pool,
143
...fs
144
}: PrimaryKey & { pool: string }) {
145
const { namespace, owner_type, owner_id, name } = primaryKey(fs);
146
// NOTE: we *could* use a heirarchy of datasets like this:
147
// ${owner_type}/${owner_id}/${name}
148
// However, that greatly increases the raw number of datasets, and there's a huge performance
149
// penalty. Since the owner_type is a fixed small list, owner_id is a uuid and the name is
150
// more general, there's no possible overlaps just concating them as below, and this way there's
151
// only one dataset, rather than three. (We also don't need to worry about deleting parents
152
// when there are no children...)
153
return `${filesystemsDataset({ pool, namespace: namespace })}/${owner_type}-${owner_id}-${name}`;
154
}
155
156
export function tempDataset({
157
pool,
158
namespace,
159
}: {
160
pool: string;
161
namespace: string;
162
}) {
163
return `${namespaceDataset({ pool, namespace })}/temp`;
164
}
165
166
export function filesystemDatasetTemp({
167
pool,
168
...fs
169
}: PrimaryKey & { pool: string }) {
170
const { namespace, owner_type, owner_id, name } = primaryKey(fs);
171
return `${tempDataset({ pool, namespace })}/${owner_type}-${owner_id}-${name}-${randomId()}`;
172
}
173
174
// NOTE: We use "join" for actual file paths and explicit
175
// strings with / for ZFS filesystem names, since in some whacky
176
// futuristic world maybe this server is running on MS Windows.
177
178