Skip to content

Commit db184aa

Browse files
committed
refactor: shard meta-schemas per draft
This introduces some new (internal-only and lazy) static entities in order to shard meta-schemas according to the draft that they belong to. Sharded meta-schemas allow to reduce the amount of registry resources that need to be constructed and statically cached.
1 parent 44520ad commit db184aa

File tree

2 files changed

+145
-38
lines changed

2 files changed

+145
-38
lines changed

crates/jsonschema-referencing/src/meta.rs

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ use std::sync::Arc;
66
use once_cell::sync::Lazy;
77
use serde_json::Value;
88

9+
use crate::Draft;
10+
911
macro_rules! schema {
1012
($vis:vis $name:ident, $path:expr) => {
1113
$vis static $name: once_cell::sync::Lazy<Arc<serde_json::Value>> =
@@ -79,7 +81,7 @@ schema!(
7981
pub DRAFT202012_CONTENT,
8082
"../metaschemas/draft2020-12/meta/content.json"
8183
);
82-
pub(crate) static META_SCHEMAS: Lazy<[(&'static str, &'static Value); 18]> = Lazy::new(|| {
84+
pub(crate) static META_SCHEMAS_ALL: Lazy<[(&'static str, &'static Value); 18]> = Lazy::new(|| {
8385
[
8486
("http://json-schema.org/draft-04/schema#", &*DRAFT4),
8587
("http://json-schema.org/draft-06/schema#", &*DRAFT6),
@@ -146,3 +148,95 @@ pub(crate) static META_SCHEMAS: Lazy<[(&'static str, &'static Value); 18]> = Laz
146148
),
147149
]
148150
});
151+
152+
pub(crate) static META_SCHEMAS_DRAFT4: Lazy<[(&'static str, &'static Value); 1]> =
153+
Lazy::new(|| [("http://json-schema.org/draft-04/schema#", &*DRAFT4)]);
154+
155+
pub(crate) static META_SCHEMAS_DRAFT6: Lazy<[(&'static str, &'static Value); 1]> =
156+
Lazy::new(|| [("http://json-schema.org/draft-06/schema#", &*DRAFT6)]);
157+
158+
pub(crate) static META_SCHEMAS_DRAFT7: Lazy<[(&'static str, &'static Value); 1]> =
159+
Lazy::new(|| [("http://json-schema.org/draft-07/schema#", &*DRAFT7)]);
160+
161+
pub(crate) static META_SCHEMAS_DRAFT2019: Lazy<[(&'static str, &'static Value); 7]> =
162+
Lazy::new(|| {
163+
[
164+
(
165+
"https://json-schema.org/draft/2019-09/schema",
166+
&*DRAFT201909,
167+
),
168+
(
169+
"https://json-schema.org/draft/2019-09/meta/applicator",
170+
&*DRAFT201909_APPLICATOR,
171+
),
172+
(
173+
"https://json-schema.org/draft/2019-09/meta/content",
174+
&*DRAFT201909_CONTENT,
175+
),
176+
(
177+
"https://json-schema.org/draft/2019-09/meta/core",
178+
&*DRAFT201909_CORE,
179+
),
180+
(
181+
"https://json-schema.org/draft/2019-09/meta/format",
182+
&*DRAFT201909_FORMAT,
183+
),
184+
(
185+
"https://json-schema.org/draft/2019-09/meta/meta-data",
186+
&*DRAFT201909_META_DATA,
187+
),
188+
(
189+
"https://json-schema.org/draft/2019-09/meta/validation",
190+
&*DRAFT201909_VALIDATION,
191+
),
192+
]
193+
});
194+
195+
pub(crate) static META_SCHEMAS_DRAFT2020: Lazy<[(&'static str, &'static Value); 8]> =
196+
Lazy::new(|| {
197+
[
198+
(
199+
"https://json-schema.org/draft/2020-12/schema",
200+
&*DRAFT202012,
201+
),
202+
(
203+
"https://json-schema.org/draft/2020-12/meta/core",
204+
&*DRAFT202012_CORE,
205+
),
206+
(
207+
"https://json-schema.org/draft/2020-12/meta/applicator",
208+
&*DRAFT202012_APPLICATOR,
209+
),
210+
(
211+
"https://json-schema.org/draft/2020-12/meta/unevaluated",
212+
&*DRAFT202012_UNEVALUATED,
213+
),
214+
(
215+
"https://json-schema.org/draft/2020-12/meta/validation",
216+
&*DRAFT202012_VALIDATION,
217+
),
218+
(
219+
"https://json-schema.org/draft/2020-12/meta/meta-data",
220+
&*DRAFT202012_META_DATA,
221+
),
222+
(
223+
"https://json-schema.org/draft/2020-12/meta/format-annotation",
224+
&*DRAFT202012_FORMAT_ANNOTATION,
225+
),
226+
(
227+
"https://json-schema.org/draft/2020-12/meta/content",
228+
&*DRAFT202012_CONTENT,
229+
),
230+
]
231+
});
232+
233+
/// Return all the meta-schemas which are part of a given draft.
234+
pub(crate) fn metas_for_draft(draft: Draft) -> &'static [(&'static str, &'static Value)] {
235+
match draft {
236+
Draft::Draft4 => &*META_SCHEMAS_DRAFT4,
237+
Draft::Draft6 => &*META_SCHEMAS_DRAFT6,
238+
Draft::Draft7 => &*META_SCHEMAS_DRAFT7,
239+
Draft::Draft201909 => &*META_SCHEMAS_DRAFT2019,
240+
Draft::Draft202012 => &*META_SCHEMAS_DRAFT2020,
241+
}
242+
}

crates/jsonschema-referencing/src/registry.rs

Lines changed: 50 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::{
1515
cache::{SharedUriCache, UriCache},
1616
hasher::BuildNoHashHasher,
1717
list::List,
18-
meta,
18+
meta::{self, metas_for_draft},
1919
resource::{unescape_segment, InnerResourcePtr, JsonSchemaResource},
2020
uri,
2121
vocabularies::{self, VocabularySet},
@@ -44,34 +44,8 @@ type DocumentStore = AHashMap<Arc<Uri<String>>, Pin<Arc<ValueWrapper>>>;
4444
type ResourceMap = AHashMap<Arc<Uri<String>>, InnerResourcePtr>;
4545

4646
/// Pre-loaded registry containing all JSON Schema meta-schemas and their vocabularies
47-
pub static SPECIFICATIONS: Lazy<Registry> = Lazy::new(|| {
48-
let pairs = meta::META_SCHEMAS.into_iter().map(|(uri, schema)| {
49-
(
50-
uri,
51-
ResourceRef::from_contents(schema).expect("Invalid resource"),
52-
)
53-
});
54-
55-
// The capacity is known upfront
56-
let mut documents = DocumentStore::with_capacity(18);
57-
let mut resources = ResourceMap::with_capacity(18);
58-
let mut anchors = AHashMap::with_capacity(8);
59-
let mut resolution_cache = UriCache::with_capacity(35);
60-
process_meta_schemas(
61-
pairs,
62-
&mut documents,
63-
&mut resources,
64-
&mut anchors,
65-
&mut resolution_cache,
66-
)
67-
.expect("Failed to process meta schemas");
68-
Registry {
69-
documents,
70-
resources,
71-
anchors,
72-
resolution_cache: resolution_cache.into_shared(),
73-
}
74-
});
47+
pub static SPECIFICATIONS: Lazy<Registry> =
48+
Lazy::new(|| Registry::build_from_meta_schemas(meta::META_SCHEMAS_ALL.as_slice()));
7549

7650
/// A registry of JSON Schema resources, each identified by their canonical URIs.
7751
///
@@ -563,6 +537,42 @@ impl Registry {
563537
_ => unreachable!(),
564538
}
565539
}
540+
541+
/// Build a registry with all the given meta-schemas from specs.
542+
pub(crate) fn build_from_meta_schemas(schemas: &[(&'static str, &'static Value)]) -> Self {
543+
let schemas_count = schemas.len();
544+
let pairs = schemas.iter().map(|(uri, schema)| {
545+
(
546+
uri,
547+
ResourceRef::from_contents(schema).expect("Invalid resource"),
548+
)
549+
});
550+
551+
let mut documents = DocumentStore::with_capacity(schemas_count);
552+
let mut resources = ResourceMap::with_capacity(schemas_count);
553+
554+
// The actual number of anchors and cache-entries varies across
555+
// drafts. We overshoot here to avoid reallocations, using the sum
556+
// over all specifications.
557+
let mut anchors = AHashMap::with_capacity(8);
558+
let mut resolution_cache = UriCache::with_capacity(35);
559+
560+
process_meta_schemas(
561+
pairs,
562+
&mut documents,
563+
&mut resources,
564+
&mut anchors,
565+
&mut resolution_cache,
566+
)
567+
.expect("Failed to process meta schemas");
568+
569+
Self {
570+
documents,
571+
resources,
572+
anchors,
573+
resolution_cache: resolution_cache.into_shared(),
574+
}
575+
}
566576
}
567577

568578
fn process_meta_schemas(
@@ -706,15 +716,18 @@ fn handle_metaschemas(
706716
refers_metaschemas: bool,
707717
resources: &mut ResourceMap,
708718
anchors: &mut AHashMap<AnchorKey, Anchor>,
719+
draft_version: Draft,
709720
) {
710721
if refers_metaschemas {
711-
resources.reserve(SPECIFICATIONS.resources.len());
712-
for (key, resource) in &SPECIFICATIONS.resources {
713-
resources.insert(Arc::clone(key), resource.clone());
722+
let schemas = metas_for_draft(draft_version);
723+
let draft_registry = Registry::build_from_meta_schemas(schemas);
724+
resources.reserve(draft_registry.resources.len());
725+
for (key, resource) in draft_registry.resources {
726+
resources.insert(key, resource.clone());
714727
}
715-
anchors.reserve(SPECIFICATIONS.anchors.len());
716-
for (key, anchor) in &SPECIFICATIONS.anchors {
717-
anchors.insert(key.clone(), anchor.clone());
728+
anchors.reserve(draft_registry.anchors.len());
729+
for (key, anchor) in draft_registry.anchors {
730+
anchors.insert(key, anchor);
718731
}
719732
}
720733
}
@@ -783,7 +796,7 @@ fn process_resources(
783796
}
784797
}
785798

786-
handle_metaschemas(state.refers_metaschemas, resources, anchors);
799+
handle_metaschemas(state.refers_metaschemas, resources, anchors, default_draft);
787800

788801
Ok(())
789802
}
@@ -860,7 +873,7 @@ async fn process_resources_async(
860873
}
861874
}
862875

863-
handle_metaschemas(state.refers_metaschemas, resources, anchors);
876+
handle_metaschemas(state.refers_metaschemas, resources, anchors, default_draft);
864877

865878
Ok(())
866879
}

0 commit comments

Comments
 (0)