123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105(** Serialization/deserialization of incremental analysis data. *)openBatteries(* TODO: GoblintDir *)letincremental_data_file_name="analysis.data"letresults_dir="results"typeoperation=Save|Load(** Returns the name of the directory used for loading/saving incremental data *)letincremental_dirnameop=matchopwith|Load->GobConfig.get_string"incremental.load-dir"|Save->GobConfig.get_string"incremental.save-dir"letgob_directoryop=GobFpath.cwd_append(Fpath.v(incremental_dirnameop))letgob_results_dirop=Fpath.(gob_directoryop/results_dir)letserver()=GobConfig.get_bool"server.enabled"letmarshalobjfileName=letchan=open_out_bin(Fpath.to_stringfileName)inMarshal.outputchanobj;close_outchanletunmarshalfileName=Logs.debug"Unmarshalling %s... If type of content changed, this will result in a segmentation fault!"(Fpath.to_stringfileName);Marshal.input(open_in_bin(Fpath.to_stringfileName))letresults_exist()=(* If Goblint did not crash irregularly, the existence of the result directory indicates that there are results *)letr=gob_results_dirLoadinletr_str=Fpath.to_stringrinSys.file_existsr_str&&Sys.is_directoryr_str(** Module to cache the data for incremental analaysis during a run, before it is stored to disk, as well as for the server mode *)moduleCache=structtypet={mutablesolver_data:Obj.toption;mutableanalysis_data:Obj.toption;mutableversion_data:MaxIdUtil.max_idsoption;mutablecil_file:GoblintCil.fileoption;}letdata=ref{solver_data=None;analysis_data=None;version_data=None;cil_file=None;}(** GADT that may be used to query data from and pass data to the cache. *)type_data_query=|SolverData:_data_query|CilFile:GoblintCil.filedata_query|VersionData:MaxIdUtil.max_idsdata_query|AnalysisData:_data_query(** Loads data for incremental runs from the appropriate file *)letload_data()=letp=Fpath.(gob_results_dirLoad/incremental_data_file_name)inletloaded_data=unmarshalpindata:=loaded_data(** Stores data for future incremental runs at the appropriate file. *)letstore_data()=GobSys.mkdir_or_exists(gob_directorySave);letd=gob_results_dirSaveinGobSys.mkdir_or_existsd;letp=Fpath.(d/incremental_data_file_name)inmarshal!datap(** Update the incremental data in the in-memory cache *)letupdate_data:typea.adata_query->a->unit=funqd->matchqwith|SolverData->!data.solver_data<-Some(Obj.reprd)|AnalysisData->!data.analysis_data<-Some(Obj.reprd)|VersionData->!data.version_data<-Somed|CilFile->!data.cil_file<-Somed(** Reset some incremental data in the in-memory cache to [None]*)letreset_data:typea.adata_query->unit=function|SolverData->!data.solver_data<-None|AnalysisData->!data.analysis_data<-None|VersionData->!data.version_data<-None|CilFile->!data.cil_file<-None(** Get incremental data from the in-memory cache wrapped in an optional.
To populate the in-memory cache with data, call [load_data] first. *)letget_opt_data:typea.adata_query->aoption=function|SolverData->Option.mapObj.obj!data.solver_data|AnalysisData->Option.mapObj.obj!data.analysis_data|VersionData->!data.version_data|CilFile->!data.cil_file(** Get incremental data from the in-memory cache.
Same as [get_opt_data], except not yielding an optional and failing when the requested data is not present. *)letget_data:typea.adata_query->a=funa->matchget_opt_dataawith|Somed->d|None->failwith"Requested data is not loaded."end