public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
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]
-=-=-=-=-=-=-=-=-=-=-=-



      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