@@ -27,6 +27,7 @@ use crate::handlers::{
27
27
CUSTOM_PARTITION_KEY , STATIC_SCHEMA_FLAG , TIME_PARTITION_KEY , TIME_PARTITION_LIMIT_KEY ,
28
28
UPDATE_STREAM_KEY ,
29
29
} ;
30
+ use crate :: hottier:: { HotTierManager , StreamHotTier } ;
30
31
use crate :: metadata:: STREAM_INFO ;
31
32
use crate :: metrics:: { EVENTS_INGESTED_DATE , EVENTS_INGESTED_SIZE_DATE , EVENTS_STORAGE_SIZE_DATE } ;
32
33
use crate :: option:: { Mode , CONFIG } ;
@@ -37,6 +38,7 @@ use crate::{
37
38
catalog:: { self , remove_manifest_from_snapshot} ,
38
39
event, stats,
39
40
} ;
41
+
40
42
use crate :: { metadata, validator} ;
41
43
use actix_web:: http:: StatusCode ;
42
44
use actix_web:: { web, HttpRequest , Responder } ;
@@ -919,6 +921,122 @@ pub async fn get_stream_info(req: HttpRequest) -> Result<impl Responder, StreamE
919
921
Ok ( ( web:: Json ( stream_info) , StatusCode :: OK ) )
920
922
}
921
923
924
+ pub async fn put_stream_hot_tier (
925
+ req : HttpRequest ,
926
+ body : web:: Json < serde_json:: Value > ,
927
+ ) -> Result < impl Responder , StreamError > {
928
+ if CONFIG . parseable . mode != Mode :: Query {
929
+ return Err ( StreamError :: Custom {
930
+ msg : "Hot tier can only be enabled in query mode" . to_string ( ) ,
931
+ status : StatusCode :: BAD_REQUEST ,
932
+ } ) ;
933
+ }
934
+ let stream_name: String = req. match_info ( ) . get ( "logstream" ) . unwrap ( ) . parse ( ) . unwrap ( ) ;
935
+ if !metadata:: STREAM_INFO . stream_exists ( & stream_name) {
936
+ return Err ( StreamError :: StreamNotFound ( stream_name) ) ;
937
+ }
938
+ if CONFIG . parseable . hot_tier_storage_path . is_none ( ) {
939
+ return Err ( StreamError :: HotTierNotEnabled ( stream_name) ) ;
940
+ }
941
+
942
+ if STREAM_INFO
943
+ . get_time_partition ( & stream_name)
944
+ . unwrap ( )
945
+ . is_some ( )
946
+ {
947
+ return Err ( StreamError :: Custom {
948
+ msg : "Hot tier can not be enabled for stream with time partition" . to_string ( ) ,
949
+ status : StatusCode :: BAD_REQUEST ,
950
+ } ) ;
951
+ }
952
+
953
+ let body = body. into_inner ( ) ;
954
+ let mut hottier: StreamHotTier = match serde_json:: from_value ( body) {
955
+ Ok ( hottier) => hottier,
956
+ Err ( err) => return Err ( StreamError :: InvalidHotTierConfig ( err) ) ,
957
+ } ;
958
+
959
+ validator:: hot_tier ( & hottier. size . to_string ( ) ) ?;
960
+
961
+ STREAM_INFO . set_hot_tier ( & stream_name, true ) ?;
962
+ if let Some ( hot_tier_manager) = HotTierManager :: global ( ) {
963
+ hot_tier_manager
964
+ . validate_hot_tier_size ( & stream_name, & hottier. size )
965
+ . await ?;
966
+ hottier. used_size = Some ( "0GiB" . to_string ( ) ) ;
967
+ hottier. available_size = Some ( hottier. size . clone ( ) ) ;
968
+ hot_tier_manager
969
+ . put_hot_tier ( & stream_name, & mut hottier)
970
+ . await ?;
971
+ let storage = CONFIG . storage ( ) . get_object_store ( ) ;
972
+ let mut stream_metadata = storage. get_object_store_format ( & stream_name) . await ?;
973
+ stream_metadata. hot_tier_enabled = Some ( true ) ;
974
+ storage
975
+ . put_stream_manifest ( & stream_name, & stream_metadata)
976
+ . await ?;
977
+ }
978
+
979
+ Ok ( (
980
+ format ! ( "hot tier set for stream {stream_name}" ) ,
981
+ StatusCode :: OK ,
982
+ ) )
983
+ }
984
+
985
+ pub async fn get_stream_hot_tier ( req : HttpRequest ) -> Result < impl Responder , StreamError > {
986
+ if CONFIG . parseable . mode != Mode :: Query {
987
+ return Err ( StreamError :: Custom {
988
+ msg : "Hot tier can only be enabled in query mode" . to_string ( ) ,
989
+ status : StatusCode :: BAD_REQUEST ,
990
+ } ) ;
991
+ }
992
+
993
+ let stream_name: String = req. match_info ( ) . get ( "logstream" ) . unwrap ( ) . parse ( ) . unwrap ( ) ;
994
+
995
+ if !metadata:: STREAM_INFO . stream_exists ( & stream_name) {
996
+ return Err ( StreamError :: StreamNotFound ( stream_name) ) ;
997
+ }
998
+
999
+ if CONFIG . parseable . hot_tier_storage_path . is_none ( ) {
1000
+ return Err ( StreamError :: HotTierNotEnabled ( stream_name) ) ;
1001
+ }
1002
+
1003
+ if let Some ( hot_tier_manager) = HotTierManager :: global ( ) {
1004
+ let hot_tier = hot_tier_manager. get_hot_tier ( & stream_name) . await ?;
1005
+ Ok ( ( web:: Json ( hot_tier) , StatusCode :: OK ) )
1006
+ } else {
1007
+ Err ( StreamError :: Custom {
1008
+ msg : format ! ( "hot tier not initialised for stream {}" , stream_name) ,
1009
+ status : ( StatusCode :: BAD_REQUEST ) ,
1010
+ } )
1011
+ }
1012
+ }
1013
+
1014
+ pub async fn delete_stream_hot_tier ( req : HttpRequest ) -> Result < impl Responder , StreamError > {
1015
+ if CONFIG . parseable . mode != Mode :: Query {
1016
+ return Err ( StreamError :: Custom {
1017
+ msg : "Hot tier can only be enabled in query mode" . to_string ( ) ,
1018
+ status : StatusCode :: BAD_REQUEST ,
1019
+ } ) ;
1020
+ }
1021
+
1022
+ let stream_name: String = req. match_info ( ) . get ( "logstream" ) . unwrap ( ) . parse ( ) . unwrap ( ) ;
1023
+
1024
+ if !metadata:: STREAM_INFO . stream_exists ( & stream_name) {
1025
+ return Err ( StreamError :: StreamNotFound ( stream_name) ) ;
1026
+ }
1027
+
1028
+ if CONFIG . parseable . hot_tier_storage_path . is_none ( ) {
1029
+ return Err ( StreamError :: HotTierNotEnabled ( stream_name) ) ;
1030
+ }
1031
+
1032
+ if let Some ( hot_tier_manager) = HotTierManager :: global ( ) {
1033
+ hot_tier_manager. delete_hot_tier ( & stream_name) . await ?;
1034
+ }
1035
+ Ok ( (
1036
+ format ! ( "hot tier deleted for stream {stream_name}" ) ,
1037
+ StatusCode :: OK ,
1038
+ ) )
1039
+ }
922
1040
#[ allow( unused) ]
923
1041
fn classify_json_error ( kind : serde_json:: error:: Category ) -> StatusCode {
924
1042
match kind {
@@ -935,9 +1053,12 @@ pub mod error {
935
1053
use http:: StatusCode ;
936
1054
937
1055
use crate :: {
1056
+ hottier:: HotTierError ,
938
1057
metadata:: error:: stream_info:: MetadataError ,
939
1058
storage:: ObjectStorageError ,
940
- validator:: error:: { AlertValidationError , StreamNameValidationError } ,
1059
+ validator:: error:: {
1060
+ AlertValidationError , HotTierValidationError , StreamNameValidationError ,
1061
+ } ,
941
1062
} ;
942
1063
943
1064
#[ allow( unused) ]
@@ -997,6 +1118,16 @@ pub mod error {
997
1118
Network ( #[ from] reqwest:: Error ) ,
998
1119
#[ error( "Could not deserialize into JSON object, {0}" ) ]
999
1120
SerdeError ( #[ from] serde_json:: Error ) ,
1121
+ #[ error(
1122
+ "Hot tier is not enabled at the server config, cannot enable hot tier for stream {0}"
1123
+ ) ]
1124
+ HotTierNotEnabled ( String ) ,
1125
+ #[ error( "failed to enable hottier due to err: {0}" ) ]
1126
+ InvalidHotTierConfig ( serde_json:: Error ) ,
1127
+ #[ error( "Hot tier validation failed due to {0}" ) ]
1128
+ HotTierValidation ( #[ from] HotTierValidationError ) ,
1129
+ #[ error( "{0}" ) ]
1130
+ HotTierError ( #[ from] HotTierError ) ,
1000
1131
}
1001
1132
1002
1133
impl actix_web:: ResponseError for StreamError {
@@ -1030,6 +1161,10 @@ pub mod error {
1030
1161
StreamError :: Network ( err) => {
1031
1162
err. status ( ) . unwrap_or ( StatusCode :: INTERNAL_SERVER_ERROR )
1032
1163
}
1164
+ StreamError :: HotTierNotEnabled ( _) => StatusCode :: BAD_REQUEST ,
1165
+ StreamError :: InvalidHotTierConfig ( _) => StatusCode :: BAD_REQUEST ,
1166
+ StreamError :: HotTierValidation ( _) => StatusCode :: BAD_REQUEST ,
1167
+ StreamError :: HotTierError ( _) => StatusCode :: INTERNAL_SERVER_ERROR ,
1033
1168
}
1034
1169
}
1035
1170
0 commit comments