From: "Nickle Wang via groups.io" <nicklew=nvidia.com@groups.io>
To: "devel@edk2.groups.io" <devel@edk2.groups.io>,
"abner.chang@amd.com" <abner.chang@amd.com>
Cc: Igor Kulchytskyy <igork@ami.com>, Nick Ramirez <nramirez@nvidia.com>
Subject: Re: [edk2-devel] [edk2-redfish-client][PATCH 01/10] RedfishClientPkg: introduce Redfish HTTP cache library
Date: Thu, 4 Jan 2024 02:33:29 +0000 [thread overview]
Message-ID: <MW4PR12MB703186C6892A763275CC9323D967A@MW4PR12MB7031.namprd12.prod.outlook.com> (raw)
In-Reply-To: <MN2PR12MB39669486EDE051600874DAB6EA60A@MN2PR12MB3966.namprd12.prod.outlook.com>
Thanks Abner. Version 2 patch series is sent for review.
Regards,
Nickle
> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Chang, Abner
> via groups.io
> Sent: Wednesday, January 3, 2024 9:02 PM
> To: Nickle Wang <nicklew@nvidia.com>; devel@edk2.groups.io
> Cc: Igor Kulchytskyy <igork@ami.com>; Nick Ramirez <nramirez@nvidia.com>
> Subject: Re: [edk2-devel] [edk2-redfish-client][PATCH 01/10] RedfishClientPkg:
> introduce Redfish HTTP cache library
>
> External email: Use caution opening links or attachments
>
>
> [AMD Official Use Only - General]
>
> Hi Nickle,
> I have no problem with this feature as we have been using this for a while. Per
> discussion off line, HttpCacheLibrary would be replaced with protocol version
> later. I would just give my RB to this patch as this patch is sent for cleaning up the
> backlogs we are going to upstream.
> But before we merging this patch, could you please replace all "BMC" term in
> these files with either Redfish service or service? Thanks.
>
> Abner
>
> > -----Original Message-----
> > From: Nickle Wang <nicklew@nvidia.com>
> > Sent: Wednesday, January 3, 2024 8:00 PM
> > To: devel@edk2.groups.io
> > Cc: Chang, Abner <Abner.Chang@amd.com>; Igor Kulchytskyy
> > <igork@ami.com>; Nick Ramirez <nramirez@nvidia.com>
> > Subject: [edk2-redfish-client][PATCH 01/10] RedfishClientPkg:
> > introduce Redfish HTTP cache library
> >
> > Caution: This message originated from an External Source. Use proper
> > caution when opening attachments, clicking links, or responding.
> >
> >
> > 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/RedfishHttpCacheLibIntern
> > al.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/EdkIIRedfishResourceConf
> > EdkIIRedfishResourceConfigLib|igLi
> > b.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/RedfishVe
> > RedfishVersionLib|rsio
> > nLib.inf
> >
> > RedfishAddendumLib|RedfishClientPkg/Library/RedfishAddendumLib/Redfis
> > hAddendumLib.inf
> >
> > RedfishDebugLib|RedfishPkg/Library/RedfishDebugLib/RedfishDebugLib.inf
> > +
> > RedfishHttpCacheLib|RedfishClientPkg/Library/RedfishHttpCacheLib/Redfi
> > RedfishHttpCacheLib|sh
> > HttpCacheLib.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..32da4f83
> > --- /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 BMC 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/RedfishHttpCacheLibInte
> > rna
> > l.h
> > b/RedfishClientPkg/Library/RedfishHttpCacheLib/RedfishHttpCacheLibInte
> > rna
> > l.h
> > new file mode 100644
> > index 00000000..2549335d
> > --- /dev/null
> > +++
> > b/RedfishClientPkg/Library/RedfishHttpCacheLib/RedfishHttpCacheLibInte
> > rna
> > l.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..c751e608
> > --- /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 BMC 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 BMC 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 (#113125): https://edk2.groups.io/g/devel/message/113125
Mute This Topic: https://groups.io/mt/103500371/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
prev parent reply other threads:[~2024-01-04 2:33 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-01-03 11:59 [edk2-devel] [edk2-redfish-client][PATCH 01/10] RedfishClientPkg: introduce Redfish HTTP cache library Nickle Wang via groups.io
2024-01-03 13:01 ` Chang, Abner via groups.io
2024-01-04 2:33 ` Nickle Wang via groups.io [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=MW4PR12MB703186C6892A763275CC9323D967A@MW4PR12MB7031.namprd12.prod.outlook.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox