@@ -1129,28 +1129,71 @@ impl LogServer {
1129
1129
let collection_id = Uuid :: parse_str ( & scout_logs. collection_id )
1130
1130
. map ( CollectionUuid )
1131
1131
. map_err ( |_| Status :: invalid_argument ( "Failed to parse collection id" ) ) ?;
1132
-
1133
1132
let prefix = collection_id. storage_prefix_for_log ( ) ;
1134
1133
let log_reader = LogReader :: new (
1135
1134
self . config . reader . clone ( ) ,
1136
1135
Arc :: clone ( & self . storage ) ,
1137
1136
prefix,
1138
1137
) ;
1139
- let ( start_position, limit_position) = match log_reader. manifest ( ) . await {
1140
- Ok ( Some ( manifest) ) => ( manifest. oldest_timestamp ( ) , manifest. next_write_timestamp ( ) ) ,
1141
- Ok ( None ) => ( LogPosition :: from_offset ( 1 ) , LogPosition :: from_offset ( 1 ) ) ,
1142
- Err ( wal3:: Error :: UninitializedLog ) => {
1143
- return Err ( Status :: not_found ( format ! (
1144
- "collection {collection_id} not found"
1145
- ) ) ) ;
1138
+ let cache_key = cache_key_for_manifest_and_etag ( collection_id) ;
1139
+ let mut cached_manifest_and_e_tag = None ;
1140
+ if let Some ( cache) = self . cache . as_ref ( ) {
1141
+ if let Some ( cache_bytes) = cache. get ( & cache_key) . await . ok ( ) . flatten ( ) {
1142
+ let met = serde_json:: from_slice :: < ManifestAndETag > ( & cache_bytes. bytes ) . ok ( ) ;
1143
+ cached_manifest_and_e_tag = met;
1146
1144
}
1147
- Err ( err) => {
1148
- return Err ( Status :: new (
1149
- err. code ( ) . into ( ) ,
1150
- format ! ( "could not scout logs: {err:?}" ) ,
1151
- ) ) ;
1145
+ }
1146
+ // NOTE(rescrv): We verify and if verification fails, we take the cached manifest to fall
1147
+ // back to the uncached path.
1148
+ if let Some ( cached) = cached_manifest_and_e_tag. as_ref ( ) {
1149
+ // Here's the linearization point. We have a cached manifest and e_tag.
1150
+ //
1151
+ // If we verify (perform a head), then statistically speaking, the manifest and e_tag
1152
+ // we have in hand is identical (barring md5 collision) to the manifest and e_tag on
1153
+ // storage. We can use the cached manifest and e_tag in this case because it is the
1154
+ // identical flow whether we read the whole manifest from storage or whether we pretend
1155
+ // to read it/verify it with a HEAD and then read out of cache.
1156
+ if !log_reader. verify ( cached) . await . unwrap_or_default ( ) {
1157
+ cached_manifest_and_e_tag. take ( ) ;
1152
1158
}
1153
- } ;
1159
+ }
1160
+ let ( start_position, limit_position) =
1161
+ if let Some ( manifest_and_e_tag) = cached_manifest_and_e_tag {
1162
+ (
1163
+ manifest_and_e_tag. manifest . oldest_timestamp ( ) ,
1164
+ manifest_and_e_tag. manifest . next_write_timestamp ( ) ,
1165
+ )
1166
+ } else {
1167
+ let ( start_position, limit_position) = match log_reader. manifest_and_e_tag ( ) . await {
1168
+ Ok ( Some ( manifest_and_e_tag) ) => {
1169
+ if let Some ( cache) = self . cache . as_ref ( ) {
1170
+ let json = serde_json:: to_string ( & manifest_and_e_tag)
1171
+ . map_err ( |err| Status :: unknown ( err. to_string ( ) ) ) ?;
1172
+ let cached_bytes = CachedBytes {
1173
+ bytes : Vec :: from ( json) ,
1174
+ } ;
1175
+ cache. insert ( cache_key, cached_bytes) . await ;
1176
+ }
1177
+ (
1178
+ manifest_and_e_tag. manifest . oldest_timestamp ( ) ,
1179
+ manifest_and_e_tag. manifest . next_write_timestamp ( ) ,
1180
+ )
1181
+ }
1182
+ Ok ( None ) => ( LogPosition :: from_offset ( 1 ) , LogPosition :: from_offset ( 1 ) ) ,
1183
+ Err ( wal3:: Error :: UninitializedLog ) => {
1184
+ return Err ( Status :: not_found ( format ! (
1185
+ "collection {collection_id} not found"
1186
+ ) ) ) ;
1187
+ }
1188
+ Err ( err) => {
1189
+ return Err ( Status :: new (
1190
+ err. code ( ) . into ( ) ,
1191
+ format ! ( "could not scout logs: {err:?}" ) ,
1192
+ ) ) ;
1193
+ }
1194
+ } ;
1195
+ ( start_position, limit_position)
1196
+ } ;
1154
1197
let start_offset = start_position. offset ( ) as i64 ;
1155
1198
let limit_offset = limit_position. offset ( ) as i64 ;
1156
1199
Ok ( Response :: new ( ScoutLogsResponse {
0 commit comments