* [edk2-devel] [edk2-redfish-client][PATCH v2 01/10] RedfishClientPkg: introduce Redfish HTTP cache library
@ 2024-01-04 2:31 Nickle Wang via groups.io
0 siblings, 0 replies; only message in thread
From: Nickle Wang via groups.io @ 2024-01-04 2:31 UTC (permalink / raw)
To: devel; +Cc: Abner Chang, Igor Kulchytskyy, Nick Ramirez
Introduce RedfishHttpCacheLib to improve HTTP GET performance
in Redfish feature drivers. Feature drivers often query same
Redfish resource multiple times for different purpose. Add
HTTP cache mechanism to improve the performance.
Signed-off-by: Nickle Wang <nicklew@nvidia.com>
Cc: Abner Chang <abner.chang@amd.com>
Cc: Igor Kulchytskyy <igork@ami.com>
Cc: Nick Ramirez <nramirez@nvidia.com>
---
RedfishClientPkg/RedfishClientPkg.dec | 3 +-
RedfishClientPkg/RedfishClientLibs.dsc.inc | 3 +-
RedfishClientPkg/RedfishClientPkg.dsc | 3 +-
.../RedfishHttpCacheLib.inf | 48 ++
.../Include/Library/RedfishHttpCacheLib.h | 59 ++
.../RedfishHttpCacheLibInternal.h | 63 ++
.../RedfishHttpCacheLib/RedfishHttpCacheLib.c | 774 ++++++++++++++++++
7 files changed, 950 insertions(+), 3 deletions(-)
create mode 100644 RedfishClientPkg/Library/RedfishHttpCacheLib/RedfishHttpCacheLib.inf
create mode 100644 RedfishClientPkg/Include/Library/RedfishHttpCacheLib.h
create mode 100644 RedfishClientPkg/Library/RedfishHttpCacheLib/RedfishHttpCacheLibInternal.h
create mode 100644 RedfishClientPkg/Library/RedfishHttpCacheLib/RedfishHttpCacheLib.c
diff --git a/RedfishClientPkg/RedfishClientPkg.dec b/RedfishClientPkg/RedfishClientPkg.dec
index 5f8a0350..b350faca 100644
--- a/RedfishClientPkg/RedfishClientPkg.dec
+++ b/RedfishClientPkg/RedfishClientPkg.dec
@@ -2,7 +2,7 @@
# Redfish Client Package
#
# (C) Copyright 2021-2022 Hewlett Packard Enterprise Development LP<BR>
-# Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+# Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
##
@@ -26,6 +26,7 @@
EdkIIRedfishResourceConfigLib|Include/Library/EdkIIRedfishResourceConfigLib.h
RedfishEventLib|Include/Library/RedfishEventLib.h
RedfishVersionLib|Include/Library/RedfishVersionLib.h
+ RedfishHttpCacheLib|Include/Library/RedfishHttpCacheLib.h
[LibraryClasses.Common.Private]
## @libraryclass Redfish Helper Library
diff --git a/RedfishClientPkg/RedfishClientLibs.dsc.inc b/RedfishClientPkg/RedfishClientLibs.dsc.inc
index 5eae6711..572f426e 100644
--- a/RedfishClientPkg/RedfishClientLibs.dsc.inc
+++ b/RedfishClientPkg/RedfishClientLibs.dsc.inc
@@ -6,7 +6,7 @@
# of EDKII network library classes.
#
# (C) Copyright 2021-2022 Hewlett Packard Enterprise Development LP<BR>
-# Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+# Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
@@ -40,3 +40,4 @@
RedfishVersionLib|RedfishClientPkg/Library/RedfishVersionLib/RedfishVersionLib.inf
RedfishAddendumLib|RedfishClientPkg/Library/RedfishAddendumLib/RedfishAddendumLib.inf
RedfishDebugLib|RedfishPkg/Library/RedfishDebugLib/RedfishDebugLib.inf
+ RedfishHttpCacheLib|RedfishClientPkg/Library/RedfishHttpCacheLib/RedfishHttpCacheLib.inf
diff --git a/RedfishClientPkg/RedfishClientPkg.dsc b/RedfishClientPkg/RedfishClientPkg.dsc
index e16c91b8..0e3ef1ac 100644
--- a/RedfishClientPkg/RedfishClientPkg.dsc
+++ b/RedfishClientPkg/RedfishClientPkg.dsc
@@ -2,7 +2,7 @@
# Redfish Client Package
#
# (C) Copyright 2021 Hewlett-Packard Enterprise Development LP.
-# Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+# Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
@@ -61,5 +61,6 @@
RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityLib.inf
RedfishClientPkg/PrivateLibrary/RedfishLib/RedfishLib.inf
RedfishClientPkg/Library/RedfishAddendumLib/RedfishAddendumLib.inf
+ RedfishClientPkg/Library/RedfishHttpCacheLib/RedfishHttpCacheLib.inf
!include RedfishClientPkg/RedfishClient.dsc.inc
diff --git a/RedfishClientPkg/Library/RedfishHttpCacheLib/RedfishHttpCacheLib.inf b/RedfishClientPkg/Library/RedfishHttpCacheLib/RedfishHttpCacheLib.inf
new file mode 100644
index 00000000..e76c8b65
--- /dev/null
+++ b/RedfishClientPkg/Library/RedfishHttpCacheLib/RedfishHttpCacheLib.inf
@@ -0,0 +1,48 @@
+## @file
+# Redfish HTTP cache library helps Redfish application to get Redfish resource
+# from Redfish service with cache mechanism enabled.
+#
+# Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010006
+ BASE_NAME = RedfishHttpCacheLib
+ FILE_GUID = 21F8FEEC-023C-451D-824D-823058FD9481
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = RedfishHttpCacheLib| DXE_DRIVER UEFI_DRIVER
+ CONSTRUCTOR = RedfishHttpCacheConstructor
+ DESTRUCTOR = RedfishHttpCacheDestructor
+
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ RedfishHttpCacheLibInternal.h
+ RedfishHttpCacheLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ RedfishPkg/RedfishPkg.dec
+ RedfishClientPkg/RedfishClientPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ RedfishLib
+ UefiLib
+ RedfishDebugLib
+ ReportStatusCodeLib
+ PrintLib
+
+[depex]
+ TRUE
+
diff --git a/RedfishClientPkg/Include/Library/RedfishHttpCacheLib.h b/RedfishClientPkg/Include/Library/RedfishHttpCacheLib.h
new file mode 100644
index 00000000..1277b981
--- /dev/null
+++ b/RedfishClientPkg/Include/Library/RedfishHttpCacheLib.h
@@ -0,0 +1,59 @@
+/** @file
+ This file defines the Redfish HTTP cache library interface.
+
+ Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef REDFISH_HTTP_CACHE_LIB_H_
+#define REDFISH_HTTP_CACHE_LIB_H_
+
+#include <Uefi.h>
+#include <Library/RedfishLib.h>
+
+/**
+ Get redfish resource from given resource URI with cache mechanism
+ supported. It's caller's responsibility to Response by calling
+ RedfishFreeResponse ().
+
+ @param[in] Service Redfish service instance to make query.
+ @param[in] Uri Target resource URI.
+ @param[out] Response HTTP response from redfish service.
+ @param[in] UseCache If it is TRUE, this function will search for
+ cache first. If it is FALSE, this function
+ will query Redfish URI directly.
+
+ @retval EFI_SUCCESS Resrouce is returned successfully.
+ @retval Others Errors occur.
+
+**/
+EFI_STATUS
+RedfishHttpGetResource (
+ IN REDFISH_SERVICE Service,
+ IN EFI_STRING Uri,
+ OUT REDFISH_RESPONSE *Response,
+ IN BOOLEAN UseCache
+ );
+
+/**
+ Reset the cached data specified by given URI. When response data
+ returned by RedfishHttpResetResource() is modified, the response
+ data can not be used by other caller. Application calls this
+ function to make this data to be stale data and
+ RedfishHttpResetResource() will get latest data from remote server
+ again.
+
+ @param[in] Uri Target resource URI.
+
+ @retval EFI_SUCCESS Resrouce is reset successfully.
+ @retval Others Errors occur.
+
+**/
+EFI_STATUS
+RedfishHttpResetResource (
+ IN EFI_STRING Uri
+ );
+
+#endif
diff --git a/RedfishClientPkg/Library/RedfishHttpCacheLib/RedfishHttpCacheLibInternal.h b/RedfishClientPkg/Library/RedfishHttpCacheLib/RedfishHttpCacheLibInternal.h
new file mode 100644
index 00000000..2549335d
--- /dev/null
+++ b/RedfishClientPkg/Library/RedfishHttpCacheLib/RedfishHttpCacheLibInternal.h
@@ -0,0 +1,63 @@
+/** @file
+ This file defines the Redfish HTTP cache library internal headers.
+
+ Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef REDFISH_HTTP_CACHE_INTERNAL_LIB_H_
+#define REDFISH_HTTP_CACHE_INTERNAL_LIB_H_
+
+#include <Uefi.h>
+#include <RedfishBase.h>
+
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/RedfishLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/RedfishHttpCacheLib.h>
+#include <Library/RedfishDebugLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/PrintLib.h>
+
+#define REDFISH_HTTP_CACHE_LIST_SIZE 0x0F
+#define REDFISH_HTTP_GET_RETRY_MAX 0x0F
+#define REDFISH_HTTP_RETRY_WAIT (2 * 1000000U) ///< 1 second
+#define REDFISH_ERROR_MSG_MAX 128
+#define REDFISH_HTTP_ERROR_REPORT "Redfish HTTP failure(0x%x): %a"
+#define REDFISH_HTTP_CACHE_DEBUG DEBUG_VERBOSE
+#define REDFISH_HTTP_CACHE_DEBUG_DUMP DEBUG_VERBOSE
+
+///
+/// Definition of REDFISH_HTTP_CACHE_DATA
+///
+typedef struct {
+ LIST_ENTRY List;
+ EFI_STRING Uri;
+ UINTN HitCount;
+ REDFISH_RESPONSE *Response;
+} REDFISH_HTTP_CACHE_DATA;
+
+#define REDFISH_HTTP_CACHE_FROM_LIST(a) BASE_CR (a, REDFISH_HTTP_CACHE_DATA, List)
+
+///
+/// Definition of REDFISH_HTTP_CACHE_LIST
+///
+typedef struct {
+ LIST_ENTRY Head;
+ UINTN Count;
+ UINTN Capacity;
+} REDFISH_HTTP_CACHE_LIST;
+
+///
+/// Definition of REDFISH_HTTP_CACHE_PRIVATE
+///
+typedef struct {
+ REDFISH_HTTP_CACHE_LIST CacheList;
+} REDFISH_HTTP_CACHE_PRIVATE;
+
+#endif
diff --git a/RedfishClientPkg/Library/RedfishHttpCacheLib/RedfishHttpCacheLib.c b/RedfishClientPkg/Library/RedfishHttpCacheLib/RedfishHttpCacheLib.c
new file mode 100644
index 00000000..be31706e
--- /dev/null
+++ b/RedfishClientPkg/Library/RedfishHttpCacheLib/RedfishHttpCacheLib.c
@@ -0,0 +1,774 @@
+/** @file
+ Redfish HTTP cache library helps Redfish application to get Redfish resource
+ from Redfish service with cache mechanism enabled.
+
+ Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RedfishHttpCacheLibInternal.h"
+
+REDFISH_HTTP_CACHE_PRIVATE *mRedfishHttpCachePrivate = NULL;
+
+/**
+ This function copy the data in SrcResponse to DstResponse.
+
+ @param[in] SrcResponse Source Response to copy.
+ @param[out] DstResponse Destination Response.
+
+ @retval EFI_SUCCESS Response is copied successfully.
+ @retval Others Error occurs.
+
+**/
+EFI_STATUS
+CopyRedfishResponse (
+ IN REDFISH_RESPONSE *SrcResponse,
+ OUT REDFISH_RESPONSE *DstResponse
+ )
+{
+ EDKII_JSON_VALUE JsonValue;
+ REDFISH_SERVICE Service;
+ UINTN Index;
+
+ if ((SrcResponse == NULL) || (DstResponse == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (SrcResponse == DstResponse) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Status code
+ //
+ if (SrcResponse->StatusCode != NULL) {
+ DstResponse->StatusCode = AllocateCopyPool (sizeof (EFI_HTTP_STATUS_CODE), SrcResponse->StatusCode);
+ if (DstResponse->StatusCode == NULL) {
+ goto ON_ERROR;
+ }
+ }
+
+ //
+ // Header
+ //
+ if ((SrcResponse->HeaderCount > 0) && (SrcResponse->Headers != NULL)) {
+ DstResponse->HeaderCount = 0;
+ DstResponse->Headers = AllocateZeroPool (sizeof (EFI_HTTP_HEADER) * SrcResponse->HeaderCount);
+ if (DstResponse->Headers == NULL) {
+ goto ON_ERROR;
+ }
+
+ for (Index = 0; Index < SrcResponse->HeaderCount; Index++) {
+ DstResponse->Headers[Index].FieldName = AllocateCopyPool (AsciiStrSize (SrcResponse->Headers[Index].FieldName), SrcResponse->Headers[Index].FieldName);
+ if (DstResponse->Headers[Index].FieldName == NULL) {
+ goto ON_ERROR;
+ }
+
+ DstResponse->Headers[Index].FieldValue = AllocateCopyPool (AsciiStrSize (SrcResponse->Headers[Index].FieldValue), SrcResponse->Headers[Index].FieldValue);
+ if (DstResponse->Headers[Index].FieldValue == NULL) {
+ goto ON_ERROR;
+ }
+
+ DstResponse->HeaderCount += 1;
+ }
+ }
+
+ //
+ // Payload
+ //
+ if (SrcResponse->Payload != NULL) {
+ Service = RedfishServiceInPayload (SrcResponse->Payload);
+ JsonValue = RedfishJsonInPayload (SrcResponse->Payload);
+ DstResponse->Payload = RedfishCreatePayload (JsonValue, Service);
+ if (DstResponse->Payload == NULL) {
+ goto ON_ERROR;
+ }
+ }
+
+ return EFI_SUCCESS;
+
+ON_ERROR:
+
+ RedfishFreeResponse (
+ DstResponse->StatusCode,
+ DstResponse->HeaderCount,
+ DstResponse->Headers,
+ DstResponse->Payload
+ );
+
+ return EFI_OUT_OF_RESOURCES;
+}
+
+/**
+ This function clone input response and return to caller
+
+ @param[in] Response Response to clone.
+
+ @retval REDFISH_RESPONSE * Response is cloned.
+ @retval NULL Errors occur.
+
+**/
+REDFISH_RESPONSE *
+CloneRedfishResponse (
+ IN REDFISH_RESPONSE *Response
+ )
+{
+ EFI_STATUS Status;
+ REDFISH_RESPONSE *NewResponse;
+
+ if (Response == NULL) {
+ return NULL;
+ }
+
+ NewResponse = AllocateZeroPool (sizeof (REDFISH_RESPONSE));
+ if (NewResponse == NULL) {
+ return NULL;
+ }
+
+ Status = CopyRedfishResponse (Response, NewResponse);
+ if (EFI_ERROR (Status)) {
+ FreePool (NewResponse);
+ return NULL;
+ }
+
+ return NewResponse;
+}
+
+/**
+
+ Convert Unicode string to ASCII string. It's call responsibility to release returned buffer.
+
+ @param[in] UnicodeStr Unicode string to convert.
+
+ @retval CHAR8 * ASCII string returned.
+ @retval NULL Errors occur.
+
+**/
+CHAR8 *
+StringUnicodeToAscii (
+ IN EFI_STRING UnicodeStr
+ )
+{
+ CHAR8 *AsciiStr;
+ UINTN AsciiStrSize;
+ EFI_STATUS Status;
+
+ if (IS_EMPTY_STRING (UnicodeStr)) {
+ return NULL;
+ }
+
+ AsciiStrSize = StrLen (UnicodeStr) + 1;
+ AsciiStr = AllocatePool (AsciiStrSize);
+ if (AsciiStr == NULL) {
+ return NULL;
+ }
+
+ Status = UnicodeStrToAsciiStrS (UnicodeStr, AsciiStr, AsciiStrSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "UnicodeStrToAsciiStrS failed: %r\n", Status));
+ FreePool (AsciiStr);
+ return NULL;
+ }
+
+ return AsciiStr;
+}
+
+/**
+ Release REDFISH_HTTP_CACHE_DATA resource
+
+ @param[in] Data Pointer to REDFISH_HTTP_CACHE_DATA instance
+
+ @retval EFI_SUCCESS REDFISH_HTTP_CACHE_DATA is released successfully.
+ @retval EFI_INVALID_PARAMETER Data is NULL
+
+**/
+EFI_STATUS
+ReleaseHttpCacheData (
+ IN REDFISH_HTTP_CACHE_DATA *Data
+ )
+{
+ if (Data == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Data->Uri != NULL) {
+ FreePool (Data->Uri);
+ }
+
+ if (Data->Response != NULL) {
+ if (Data->Response->Payload != NULL) {
+ RedfishFreeResponse (
+ Data->Response->StatusCode,
+ Data->Response->HeaderCount,
+ Data->Response->Headers,
+ Data->Response->Payload
+ );
+ FreePool (Data->Response);
+ }
+ }
+
+ FreePool (Data);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create new cache data.
+
+ @param[in] Uri The URI string matching to this cache data.
+ @param[in] Response HTTP response.
+
+ @retval REDFISH_HTTP_CACHE_DATA * Pointer to newly created cache data.
+ @retval NULL No memory available.
+
+**/
+REDFISH_HTTP_CACHE_DATA *
+NewHttpCacheData (
+ IN EFI_STRING Uri,
+ IN REDFISH_RESPONSE *Response
+ )
+{
+ REDFISH_HTTP_CACHE_DATA *NewData;
+ UINTN Size;
+
+ if (IS_EMPTY_STRING (Uri) || (Response == NULL)) {
+ return NULL;
+ }
+
+ NewData = AllocateZeroPool (sizeof (REDFISH_HTTP_CACHE_DATA));
+ if (NewData == NULL) {
+ return NULL;
+ }
+
+ Size = StrSize (Uri);
+ NewData->Uri = AllocateCopyPool (Size, Uri);
+ if (NewData->Uri == NULL) {
+ goto ON_ERROR;
+ }
+
+ NewData->Response = Response;
+ NewData->HitCount = 1;
+
+ return NewData;
+
+ON_ERROR:
+
+ if (NewData != NULL) {
+ ReleaseHttpCacheData (NewData);
+ }
+
+ return NULL;
+}
+
+/**
+ Search on given ListHeader for given URI string.
+
+ @param[in] ListHeader Target list to search.
+ @param[in] Uri Target URI to search.
+
+ @retval REDFISH_HTTP_CACHE_DATA Target cache data is found.
+ @retval NULL No cache data with given URI is found.
+
+**/
+REDFISH_HTTP_CACHE_DATA *
+FindHttpCacheData (
+ IN LIST_ENTRY *ListHeader,
+ IN EFI_STRING Uri
+ )
+{
+ LIST_ENTRY *List;
+ REDFISH_HTTP_CACHE_DATA *Data;
+
+ if (IS_EMPTY_STRING (Uri)) {
+ return NULL;
+ }
+
+ if (IsListEmpty (ListHeader)) {
+ return NULL;
+ }
+
+ Data = NULL;
+ List = GetFirstNode (ListHeader);
+ while (!IsNull (ListHeader, List)) {
+ Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
+
+ if (StrCmp (Data->Uri, Uri) == 0) {
+ return Data;
+ }
+
+ List = GetNextNode (ListHeader, List);
+ }
+
+ return NULL;
+}
+
+/**
+ Search on given ListHeader and return cache data with minimum hit count.
+
+ @param[in] ListHeader Target list to search.
+
+ @retval REDFISH_HTTP_CACHE_DATA Target cache data is returned.
+ @retval NULL No cache data is found.
+
+**/
+REDFISH_HTTP_CACHE_DATA *
+FindUnusedHttpCacheData (
+ IN LIST_ENTRY *ListHeader
+ )
+{
+ LIST_ENTRY *List;
+ REDFISH_HTTP_CACHE_DATA *Data;
+ REDFISH_HTTP_CACHE_DATA *UnusedData;
+ UINTN HitCount;
+
+ if (IsListEmpty (ListHeader)) {
+ return NULL;
+ }
+
+ Data = NULL;
+ UnusedData = NULL;
+ HitCount = 0;
+
+ List = GetFirstNode (ListHeader);
+ Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
+ UnusedData = Data;
+ HitCount = Data->HitCount;
+ List = GetNextNode (ListHeader, List);
+
+ while (!IsNull (ListHeader, List)) {
+ Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
+
+ if (Data->HitCount < HitCount) {
+ HitCount = Data->HitCount;
+ UnusedData = Data;
+ }
+
+ List = GetNextNode (ListHeader, List);
+ }
+
+ return UnusedData;
+}
+
+/**
+ Delete a cache data by given cache instance.
+
+ @param[in] List Target cache list to be removed.
+ @param[in] Data Pointer to the instance to be deleted.
+
+ @retval EFI_SUCCESS Cache data is removed.
+ @retval Others Fail to remove cache data.
+
+**/
+EFI_STATUS
+DeleteHttpCacheData (
+ IN REDFISH_HTTP_CACHE_LIST *List,
+ IN REDFISH_HTTP_CACHE_DATA *Data
+ )
+{
+ if ((List == NULL) || (Data == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: delete: %s\n", __func__, Data->Uri));
+
+ RemoveEntryList (&Data->List);
+ --List->Count;
+
+ return ReleaseHttpCacheData (Data);
+}
+
+/**
+ Add new cache by given URI and HTTP response to specify List.
+
+ @param[in] List Target cache list to add.
+ @param[in] Uri The URI string matching to this cache data.
+ @param[in] Response HTTP response.
+
+ @retval EFI_SUCCESS Cache data is added.
+ @retval Others Fail to add cache data.
+
+**/
+EFI_STATUS
+AddHttpCacheData (
+ IN REDFISH_HTTP_CACHE_LIST *List,
+ IN EFI_STRING Uri,
+ IN REDFISH_RESPONSE *Response
+ )
+{
+ REDFISH_HTTP_CACHE_DATA *NewData;
+ REDFISH_HTTP_CACHE_DATA *OldData;
+ REDFISH_HTTP_CACHE_DATA *UnusedData;
+ REDFISH_RESPONSE *NewResponse;
+
+ if ((List == NULL) || IS_EMPTY_STRING (Uri) || (Response == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If same cache data exist, replace it with latest one.
+ //
+ OldData = FindHttpCacheData (&List->Head, Uri);
+ if (OldData != NULL) {
+ DeleteHttpCacheData (List, OldData);
+ }
+
+ //
+ // Check capacity
+ //
+ if (List->Count >= List->Capacity) {
+ DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: list is full and retire unused cache\n", __func__));
+ UnusedData = FindUnusedHttpCacheData (&List->Head);
+ if (UnusedData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DeleteHttpCacheData (List, UnusedData);
+ }
+
+ //
+ // Clone a local copy
+ //
+ NewResponse = CloneRedfishResponse (Response);
+ if (NewResponse == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewData = NewHttpCacheData (Uri, NewResponse);
+ if (NewData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ InsertTailList (&List->Head, &NewData->List);
+ ++List->Count;
+
+ DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: cache(%d/%d) %s\n", __func__, List->Count, List->Capacity, NewData->Uri));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Release all cache from list.
+
+ @param[in] CacheList The list to be released.
+
+ @retval EFI_SUCCESS All cache data are released.
+ @retval EFI_INVALID_PARAMETER CacheList is NULL.
+
+**/
+EFI_STATUS
+ReleaseCacheList (
+ IN REDFISH_HTTP_CACHE_LIST *CacheList
+ )
+{
+ LIST_ENTRY *List;
+ LIST_ENTRY *Next;
+ REDFISH_HTTP_CACHE_DATA *Data;
+
+ if (CacheList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IsListEmpty (&CacheList->Head)) {
+ return EFI_SUCCESS;
+ }
+
+ Data = NULL;
+ Next = NULL;
+ List = GetFirstNode (&CacheList->Head);
+ while (!IsNull (&CacheList->Head, List)) {
+ Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
+ Next = GetNextNode (&CacheList->Head, List);
+
+ DeleteHttpCacheData (CacheList, Data);
+
+ List = Next;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Debug output the cache list.
+
+ @param[in] Msg Debug message string.
+ @param[in] ErrorLevel Output error level.
+ @param[in] CacheList Target list to dump.
+
+ @retval EFI_SUCCESS Debug dump finished.
+ @retval EFI_INVALID_PARAMETER HttpCacheList is NULL.
+
+**/
+EFI_STATUS
+DumpHttpCacheList (
+ IN CONST CHAR8 *Msg,
+ IN UINTN ErrorLevel,
+ IN REDFISH_HTTP_CACHE_LIST *CacheList
+ )
+{
+ LIST_ENTRY *List;
+ REDFISH_HTTP_CACHE_DATA *Data;
+ UINTN Index;
+
+ if (CacheList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!IS_EMPTY_STRING (Msg)) {
+ DEBUG ((ErrorLevel, "%a\n", Msg));
+ }
+
+ if (IsListEmpty (&CacheList->Head)) {
+ DEBUG ((ErrorLevel, "list is empty\n"));
+ return EFI_NOT_FOUND;
+ }
+
+ DEBUG ((ErrorLevel, "list count: %d capacity: %d\n", CacheList->Count, CacheList->Capacity));
+ Data = NULL;
+ Index = 0;
+ List = GetFirstNode (&CacheList->Head);
+ while (!IsNull (&CacheList->Head, List)) {
+ Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
+
+ DEBUG ((ErrorLevel, "%d) Uri: %s Hit: %d\n", ++Index, Data->Uri, Data->HitCount));
+
+ List = GetNextNode (&CacheList->Head, List);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get redfish resource from given resource URI with cache mechanism
+ supported. It's caller's responsibility to Response by calling
+ RedfishFreeResponse ().
+
+ @param[in] Service Redfish service instance to make query.
+ @param[in] Uri Target resource URI.
+ @param[out] Response HTTP response from redfish service.
+ @param[in] UseCache If it is TRUE, this function will search for
+ cache first. If it is FALSE, this function
+ will query Redfish URI directly.
+
+ @retval EFI_SUCCESS Resrouce is returned successfully.
+ @retval Others Errors occur.
+
+**/
+EFI_STATUS
+RedfishHttpGetResource (
+ IN REDFISH_SERVICE Service,
+ IN EFI_STRING Uri,
+ OUT REDFISH_RESPONSE *Response,
+ IN BOOLEAN UseCache
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 *AsciiUri;
+ REDFISH_HTTP_CACHE_DATA *CacheData;
+ UINTN RetryCount;
+
+ if ((Service == NULL) || (Response == NULL) || IS_EMPTY_STRING (Uri)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (mRedfishHttpCachePrivate == NULL) {
+ return EFI_NOT_READY;
+ }
+
+ AsciiUri = NULL;
+ CacheData = NULL;
+ RetryCount = 0;
+
+ //
+ // Search for cache list.
+ //
+ if (UseCache) {
+ CacheData = FindHttpCacheData (&mRedfishHttpCachePrivate->CacheList.Head, Uri);
+ if (CacheData != NULL) {
+ DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: cache hit! %s\n", __func__, Uri));
+
+ //
+ // Copy cached response to caller's buffer.
+ //
+ Status = CopyRedfishResponse (CacheData->Response, Response);
+ CacheData->HitCount += 1;
+ return Status;
+ }
+ }
+
+ AsciiUri = StringUnicodeToAscii (Uri);
+ if (AsciiUri == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Get resource from redfish service.
+ //
+ do {
+ RetryCount += 1;
+ Status = RedfishGetByUri (
+ Service,
+ AsciiUri,
+ Response
+ );
+ if (!EFI_ERROR (Status) || (RetryCount >= REDFISH_HTTP_GET_RETRY_MAX)) {
+ break;
+ }
+
+ //
+ // Retry when Redfish service is not ready.
+ //
+ if ((Response->StatusCode != NULL)) {
+ DEBUG_CODE (
+ DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
+ );
+
+ if (*Response->StatusCode != HTTP_STATUS_500_INTERNAL_SERVER_ERROR) {
+ break;
+ }
+
+ FreePool (Response->StatusCode);
+ Response->StatusCode = NULL;
+ }
+
+ DEBUG ((DEBUG_WARN, "%a: RedfishGetByUri failed, retry (%d/%d)\n", __func__, RetryCount, REDFISH_HTTP_GET_RETRY_MAX));
+ gBS->Stall (REDFISH_HTTP_RETRY_WAIT);
+ } while (TRUE);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: get %a failed (%d/%d): %r\n", __func__, AsciiUri, RetryCount, REDFISH_HTTP_GET_RETRY_MAX, Status));
+ if (Response->Payload != NULL) {
+ RedfishFreeResponse (
+ NULL,
+ 0,
+ NULL,
+ Response->Payload
+ );
+ Response->Payload = NULL;
+ }
+
+ goto ON_RELEASE;
+ }
+
+ //
+ // Keep response in cache list
+ //
+ Status = AddHttpCacheData (&mRedfishHttpCachePrivate->CacheList, Uri, Response);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: failed to cache %s: %r\n", __func__, Uri, Status));
+ goto ON_RELEASE;
+ }
+
+ DEBUG_CODE (
+ DumpHttpCacheList (__func__, REDFISH_HTTP_CACHE_DEBUG_DUMP, &mRedfishHttpCachePrivate->CacheList);
+ );
+
+ON_RELEASE:
+
+ if (AsciiUri != NULL) {
+ FreePool (AsciiUri);
+ }
+
+ return Status;
+}
+
+/**
+ Reset the cached data specified by given URI. When response data
+ returned by RedfishHttpResetResource() is modified, the response
+ data can not be used by other caller. Application calls this
+ function to make this data to be stale data and
+ RedfishHttpResetResource() will get latest data from remote server
+ again.
+
+ @param[in] Uri Target resource URI.
+
+ @retval EFI_SUCCESS Resrouce is reset successfully.
+ @retval Others Errors occur.
+
+**/
+EFI_STATUS
+RedfishHttpResetResource (
+ IN EFI_STRING Uri
+ )
+{
+ REDFISH_HTTP_CACHE_DATA *CacheData;
+
+ if (IS_EMPTY_STRING (Uri)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (mRedfishHttpCachePrivate == NULL) {
+ return EFI_NOT_READY;
+ }
+
+ CacheData = FindHttpCacheData (&mRedfishHttpCachePrivate->CacheList.Head, Uri);
+ if (CacheData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ DeleteHttpCacheData (&mRedfishHttpCachePrivate->CacheList, CacheData);
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Initial HTTP cache library instance.
+
+ @param[in] ImageHandle The image handle.
+ @param[in] SystemTable The system table.
+
+ @retval EFI_SUCCESS Initial library successfully.
+ @retval Other Return error status.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishHttpCacheConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ mRedfishHttpCachePrivate = AllocateZeroPool (sizeof (REDFISH_HTTP_CACHE_PRIVATE));
+ if (mRedfishHttpCachePrivate == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Initial cache list
+ //
+ mRedfishHttpCachePrivate->CacheList.Capacity = REDFISH_HTTP_CACHE_LIST_SIZE;
+ mRedfishHttpCachePrivate->CacheList.Count = 0x00;
+ InitializeListHead (&mRedfishHttpCachePrivate->CacheList.Head);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Release allocated resource.
+
+ @param[in] ImageHandle Handle that identifies the image to be unloaded.
+ @param[in] SystemTable The system table.
+
+ @retval EFI_SUCCESS The image has been unloaded.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishHttpCacheDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ if (mRedfishHttpCachePrivate != NULL) {
+ if (!IsListEmpty (&mRedfishHttpCachePrivate->CacheList.Head)) {
+ ReleaseCacheList (&mRedfishHttpCachePrivate->CacheList);
+ }
+
+ FreePool (mRedfishHttpCachePrivate);
+ mRedfishHttpCachePrivate = NULL;
+ }
+
+ return EFI_SUCCESS;
+}
--
2.34.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#113114): https://edk2.groups.io/g/devel/message/113114
Mute This Topic: https://groups.io/mt/103515954/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2024-01-04 2:31 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-01-04 2:31 [edk2-devel] [edk2-redfish-client][PATCH v2 01/10] RedfishClientPkg: introduce Redfish HTTP cache library Nickle Wang via groups.io
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox