Skip to content

Commit 9c255d6

Browse files
committed
setup sharded state
1 parent 7e604db commit 9c255d6

File tree

8 files changed

+814
-87
lines changed

8 files changed

+814
-87
lines changed

packages/atlas-service/src/make-automation-agent-op-request.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ export type AutomationAgentRequestTypes = {
1919
collection: string;
2020
name: string;
2121
};
22+
getShardKey: ClusterOrServerlessId & {
23+
db: string;
24+
collection: string;
25+
};
2226
};
2327

2428
type AutomationAgentRequestOpTypes = keyof AutomationAgentRequestTypes;
@@ -60,6 +64,11 @@ export type AutomationAgentAwaitResponseTypes = {
6064
status: 'rolling build' | 'building' | 'exists';
6165
}[];
6266
dropIndex: never[];
67+
getShardKey: Array<{
68+
_id: string;
69+
unique: boolean;
70+
key: Record<string, unknown>;
71+
}>;
6372
};
6473

6574
type AutomationAgentAwaitOpTypes = keyof AutomationAgentAwaitResponseTypes;
@@ -121,6 +130,10 @@ function unwrapAutomationAgentAwaitResponse(
121130
json: any,
122131
opType: 'dropIndex'
123132
): UnwrappedAutomationAgentAwaitResponse<'dropIndex'>;
133+
function unwrapAutomationAgentAwaitResponse(
134+
json: any,
135+
opType: 'getShardKey'
136+
): UnwrappedAutomationAgentAwaitResponse<'getShardKey'>;
124137
function unwrapAutomationAgentAwaitResponse(json: any, opType: string): never;
125138
function unwrapAutomationAgentAwaitResponse(
126139
json: any,
@@ -136,6 +149,10 @@ function unwrapAutomationAgentAwaitResponse(
136149
assertAutomationAgentAwaitResponse(json, opType);
137150
return json.response;
138151
}
152+
if (opType === 'getShardKey') {
153+
assertAutomationAgentAwaitResponse(json, opType);
154+
return json.response;
155+
}
139156
throw new Error(`Unsupported await response type: ${opType}`);
140157
}
141158

packages/compass-global-writes/src/components/index.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import type { RootState, ShardingStatus } from '../store/reducer';
1010
import { ShardingStatuses } from '../store/reducer';
1111
import UnshardedState from './states/unsharded';
1212
import ShardingState from './states/sharding';
13+
import ShardKeyCorrect from './states/shard-key-correct';
1314

1415
const containerStyles = css({
1516
paddingLeft: spacing[400],
@@ -58,6 +59,13 @@ function ShardingStateView({
5859
return <ShardingState />;
5960
}
6061

62+
if (
63+
shardingStatus === ShardingStatuses.SHARD_KEY_CORRECT ||
64+
shardingStatus === ShardingStatuses.UNMANAGING_NAMESPACE
65+
) {
66+
return <ShardKeyCorrect />;
67+
}
68+
6169
return null;
6270
}
6371

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import React from 'react';
2+
import {
3+
Table,
4+
TableBody,
5+
TableHead,
6+
HeaderRow,
7+
HeaderCell,
8+
Row,
9+
Cell,
10+
css,
11+
} from '@mongodb-js/compass-components';
12+
import type { ShardZoneData } from '../store/reducer';
13+
14+
const containerStyles = css({
15+
maxWidth: '700px',
16+
height: '400px',
17+
});
18+
19+
export function ShardZonesTable({
20+
shardZones,
21+
}: {
22+
shardZones: ShardZoneData[];
23+
}) {
24+
return (
25+
// TODO: Add option to search and group zones by ShardZoneData.typeOneIsoCode
26+
// and display them in nested row
27+
<Table className={containerStyles} title="Zone Mapping">
28+
<TableHead isSticky>
29+
<HeaderRow>
30+
<HeaderCell>Location Name</HeaderCell>
31+
<HeaderCell>Zone</HeaderCell>
32+
</HeaderRow>
33+
</TableHead>
34+
<TableBody>
35+
{shardZones.map((shardZone, index) => {
36+
return (
37+
<Row key={index}>
38+
<Cell>{shardZone.country}</Cell>
39+
<Cell>
40+
{shardZone.zoneName}({shardZone.zoneLocations.join(', ')})
41+
</Cell>
42+
</Row>
43+
);
44+
})}
45+
</TableBody>
46+
</Table>
47+
);
48+
}
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
import React, { useMemo } from 'react';
2+
import {
3+
Banner,
4+
BannerVariant,
5+
Body,
6+
css,
7+
Link,
8+
spacing,
9+
Code,
10+
Subtitle,
11+
Label,
12+
SpinLoader,
13+
Button,
14+
} from '@mongodb-js/compass-components';
15+
import { connect } from 'react-redux';
16+
import {
17+
ShardingStatuses,
18+
unmanageNamespace,
19+
type RootState,
20+
type ShardKey,
21+
type ShardZoneData,
22+
} from '../../store/reducer';
23+
import toNS from 'mongodb-ns';
24+
import { ShardZonesTable } from '../shard-zones-table';
25+
26+
const nbsp = '\u00a0';
27+
28+
const containerStyles = css({
29+
display: 'flex',
30+
flexDirection: 'column',
31+
gap: spacing[400],
32+
});
33+
34+
const codeBlockContainerStyles = css({
35+
display: 'flex',
36+
flexDirection: 'column',
37+
gap: spacing[100],
38+
maxWidth: '700px',
39+
});
40+
41+
const paragraphStyles = css({
42+
display: 'flex',
43+
flexDirection: 'column',
44+
gap: spacing[100],
45+
});
46+
47+
type ShardKeyCorrectProps = {
48+
namespace: string;
49+
shardKey: ShardKey;
50+
shardZones: ShardZoneData[];
51+
isUnmanagingNamespace: boolean;
52+
onUnmanageNamespace: () => void;
53+
};
54+
55+
export function ShardKeyCorrect({
56+
namespace,
57+
shardKey,
58+
shardZones,
59+
isUnmanagingNamespace,
60+
onUnmanageNamespace,
61+
}: ShardKeyCorrectProps) {
62+
const customShardKeyField = useMemo(() => {
63+
return shardKey.fields[1].name;
64+
}, [shardKey]);
65+
66+
const sampleCodes = useMemo(() => {
67+
const { collection } = toNS(namespace);
68+
return {
69+
findingDocuments: `use ${collection}\ndb.${collection}.find({"location": "US-NY", "${customShardKeyField}": "<id_value>"})`,
70+
insertingDocuments: `use ${collection}\ndb.${collection}.insertOne({"location": "US-NY", "${customShardKeyField}": "<id_value>",...<other fields>})`,
71+
};
72+
}, [namespace, customShardKeyField]);
73+
74+
return (
75+
<div className={containerStyles}>
76+
<Banner variant={BannerVariant.Info}>
77+
<strong>
78+
All documents in your collection should contain both the ‘location’
79+
field (with a ISO country or subdivision code) and your{' '}
80+
{customShardKeyField} field at insert time.
81+
</strong>
82+
{nbsp}We have included a table for reference below.
83+
</Banner>
84+
85+
<div className={codeBlockContainerStyles}>
86+
<Body>
87+
<strong>{namespace}</strong> is configured with the following shard
88+
key:
89+
</Body>
90+
<Code language="js">{namespace}</Code>
91+
</div>
92+
93+
<Subtitle>Example commands</Subtitle>
94+
<div className={paragraphStyles}>
95+
<Body>
96+
Start querying your database with some of the most{' '}
97+
<Link
98+
href="https://www.mongodb.com/docs/atlas/global-clusters"
99+
hideExternalIcon
100+
>
101+
common commands
102+
</Link>{' '}
103+
for Global Writes.
104+
</Body>
105+
<Body>
106+
Replace the text to perform operations on different documents. US-NY
107+
is an ISO 3166 location code referring to New York, United States. You
108+
can look up other ISO 3166 location codes below.
109+
</Body>
110+
</div>
111+
112+
<div className={codeBlockContainerStyles}>
113+
<Label htmlFor="finding-documents">Finding documents</Label>
114+
<Code language="js">{sampleCodes.findingDocuments}</Code>
115+
</div>
116+
117+
<div className={codeBlockContainerStyles}>
118+
<Label htmlFor="inserting-documents">Inserting documents</Label>
119+
<Code language="js">{sampleCodes.insertingDocuments}</Code>
120+
</div>
121+
122+
<Subtitle>Location Codes</Subtitle>
123+
<div className={paragraphStyles}>
124+
<Body>
125+
Each document’s first field should include an ISO 3166-1 Alpha-2 code
126+
for the location it belongs to.
127+
</Body>
128+
<Body>
129+
We also support ISO 3166-2 subdivision codes for countries containing
130+
a cloud provider data center (both ISO 3166-1 and ISO 3166-2 codes may
131+
be used for these countries). All valid country codes and the zones to
132+
which they map are listed in the table below. Additionally, you can
133+
view a list of all location codes{' '}
134+
<Link
135+
href="https://cloud-dev.mongodb.com/static/atlas/country_iso_codes.txt"
136+
hideExternalIcon
137+
>
138+
here
139+
</Link>
140+
.
141+
</Body>
142+
<Body>
143+
Locations’ zone mapping can be changed by navigating to this clusters{' '}
144+
<Link
145+
hideExternalIcon
146+
href="https://cloud-dev.mongodb.com/v2/66bb81dafe547055785904a3#/clusters/edit/Cluster0"
147+
>
148+
Edit Configuration
149+
</Link>{' '}
150+
page and clicking the Configure Location Mappings’ link above the map.
151+
</Body>
152+
</div>
153+
154+
<ShardZonesTable shardZones={shardZones} />
155+
156+
<Subtitle>Unmanage this collection</Subtitle>
157+
<Body>
158+
Documents belonging to this collection will no longer be distributed
159+
across the shards of your global clusters.
160+
</Body>
161+
<div>
162+
<Button
163+
data-testid="shard-collection-button"
164+
onClick={onUnmanageNamespace}
165+
disabled={isUnmanagingNamespace}
166+
variant="primary"
167+
leftGlyph={
168+
isUnmanagingNamespace ? (
169+
<SpinLoader title="Unmanaging collection" />
170+
) : undefined
171+
}
172+
>
173+
Unmanage collection
174+
</Button>
175+
</div>
176+
</div>
177+
);
178+
}
179+
180+
export default connect(
181+
(state: RootState) => ({
182+
namespace: state.namespace,
183+
// For this view, sharKey is always defined
184+
shardKey: state.shardKey as ShardKey,
185+
shardZones: state.shardZones,
186+
isUnmanagingNamespace:
187+
state.status === ShardingStatuses.UNMANAGING_NAMESPACE,
188+
}),
189+
{
190+
onUnmanageNamespace: unmanageNamespace,
191+
}
192+
)(ShardKeyCorrect);

packages/compass-global-writes/src/plugin-title.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ const PluginTitle = ({ showWarning }: { showWarning: boolean }) => {
7272
};
7373

7474
export const GlobalWritesTabTitle = connect(
75-
({ isNamespaceSharded, status }: RootState) => ({
76-
showWarning: !isNamespaceSharded && status !== ShardingStatuses.NOT_READY,
75+
({ managedNamespace, status }: RootState) => ({
76+
showWarning: !managedNamespace && status !== ShardingStatuses.NOT_READY,
7777
})
7878
)(PluginTitle);

0 commit comments

Comments
 (0)