이번 포스팅에서는 인텔 Hyperscan의 공식 문서를 통해 컴파일(compile)이나 스캔(scan)과 같은 Hyperscan의 기본적인 개념들에 대해 알아보도록 하겠습니다. 추후에는 Hyperscan API를 직접 사용하여 정규 표현식 패턴 매칭을 수행하는 샘플 코드도 업로드할 예정입니다.


목차

  1. 1. Introduction
    1. 1.1. Compilation
    2. 1.2. Scanning
  2. 2. Compiling Patterns
    1. 2.1. Building a Database
    2. 2.2. Pattern Support
      1. 2.2.1. Supported Constructs
    3. 2.3. Semantics
      1. 2.3.1. Start of Match(SOM)
  3. 3. Scanning for Patterns
    1. 3.1. Handling Matches
    2. 3.2. Streaming Mode
    3. 3.3. Block Mode
    4. 3.4. Vectored Mode
    5. 3.5. Scratch Space

Introduction

Hyperscan은 높은 성능과 유연성을 고려하여 디자인된 정규 표현식 매칭 엔진 소프트웨어 입니다. 이것은 직관적인 C API 형태의 라이브러리로 구현되었습니다.

Hyperscan is a software regular expression matching engine designed with high performance and flexibility in mind. It is implemented as a library that exposes a straightforward C API.


Hyperscan API는 2가지 요소(compilationscanning)로 구성되어 있습니다.

The Hyperscan API itself is composed of two major components:


Compilation

이 함수들은 식별자나 옵션 플래그값에 따른 정규 표현식 그룹을 전달받아 Hyperscan의 scanning API에서 사용하는 변경이 불가한 데이터베이스 형태로 변환(compile)합니다. 이 변환 과정에서 주어진 표현식들을 효율적으로 매칭하기위한 데이터베이스를 생성하기 위해 많은 양의 분석 및 최적화 작업을 수행합니다.

These functions take a group of regular expressions, along with identifiers and option flags, and compile them into an immutable database that can be used by the Hyperscan scanning API. This compilation process performs considerable analysis and optimization work in order to build a database that will match the given expressions efficiently.


만약 (Hyperscan에서 지원하지 않는 정규표현식을 사용하거나 리소스 임계치 초과와 같은)어떠한 이유에서든 특정 패턴이 데이터베이스화되지 않는다면 패턴 컴파일러에 의해 에러가 반환될 것입니다.

If a pattern cannot be built into a database for any reason (such as the use of an unsupported expression construct, or the overflowing of a resource limit), an error will be returned by the pattern compiler.


변환된 데이터베이스는 직렬화되거나 재배치될 수 있으며 이를 통해 디스크에 저장되거나 호스트 간 이동이 가능합니다. 또한 이 데이터베이스는 특정한 플랫폼 특성의 대상이 될 수 있습니다. (예를 들어, Intel® AVX2 지시어의 사용)

Compiled databases can be serialized and relocated, so that they can be stored to disk or moved between hosts. They can also be targeted to particular platform features (for example, the use of Intel® Advanced Vector Extensions 2 (Intel® AVX2) instructions).


Scanning

일단 Hyperscan 데이터베이스가 생성이 된다면, 이 데이터베이스는 메모리 상에 있는 데이터를 스캔하기 위해 사용될 수 있습니다. Hyperscan은 몇가지 스캐닝 모드를 제공하는데, 이 모드는 스캔한 데이터가 단일 인접 블록(single contiguous block)으로 사용이 가능한지, 메모리에 있는 몇몇 블록에 동시에 분배가 가능한지 또는 스트림 안에서 일련의 블록(sequence of blocks)으로 스캔되는지에 따라 결정됩니다.

Once a Hyperscan database has been created, it can be used to scan data in memory. Hyperscan provides several scanning modes, depending on whether the data to be scanned is available as a single contiguous block, whether it is distributed amongst several blocks in memory at the same time, or whether it is to be scanned as a sequence of blocks in a stream.


매칭된 정보는 각각의 매칭 과정에서 동기적으로 호출되는 사용자 정의 콜백 함수를 통해 어플리케이션으로 전달됩니다.

Matches are delivered to the application via a user-supplied callback function that is called synchronously for each match.


주어진 데이터베이스에 대해, Hyperscan은 몇가지 보장들을 제공합니다.

For a given database, Hyperscan provides several guarantees:


  • 2가지 고정 사이즈 할당을 제외하면 런타임시에 메모리 할당은 발생하지 않으며, 2가지 고정 사이즈 할당 과정은 반드시 performance-critical 어플리케이션 전에 끝나야합니다.
    • 스크래치 공간: 스캔 시점에 내부 데이터에 사용되는 임시 메모리 공간입니다. 단일 스캔 호출이 끝난 이후에 scratch 공간 내의 구조들은 유지되지 않습니다.
    • 스트림 공간: 스트리밍 모드인 경우에만 해당하며, 각각의 스트림에 대한 스캔 호출 사이에서 유지되는 데이터를 저장하기 위해 몇몇 상태 공간이 요구됩니다. 이를 통해 Hyperscan은 복수의 데이터 블록에 걸쳐 매칭되는 정보를 트랙킹할 수 있습니다.
  • 주어진 데이터베이스에서 요구하는 scratch 공간 및 stream 상태(스트리밍 모드에서) 공간의 크기는 고정되어있으며 데이터베이스 컴파일 타임에 결정됩니다. 이는 어플리케이션의 메모리 요구사항을 사전에 알 수 있다는 의미이며, 성능상의 이유로 필요한 경우라면, 이러한 구조들은 미리 할당될 수 있습니다.
  • Hyperscan 컴파일러에 의해 정상적으로 컴파일된 패턴이라면 어떠한 입력 값이 들어오더라도 스캔이 가능합니다. 런타임 시 스캔 호출이 에러를 반환하도록 하는 내부적인 리소스 제한이나 다른 제약사항들은 없습니다.
  • No memory allocations occur at runtime with the exception of two fixed-size allocations, both of which should be done ahead of time for performance-critical applications:
    • Scratch space: temporary memory used for internal data at scan time. Structures in scratch space do not persist beyond the end of a single scan call.
    • Stream state: in streaming mode only, some state space is required to store data that persists between scan calls for each stream. This allows Hyperscan to track matches that span multiple blocks of data.
  • The sizes of the scratch space and stream state (in streaming mode) required for a given database are fixed and determined at database compile time. This means that the memory requirements of the application are known ahead of time, and these structures can be pre-allocated if required for performance reasons.
  • Any pattern that has successfully been compiled by the Hyperscan compiler can be scanned against any input. There are no internal resource limits or other limitations at runtime that could cause a scan call to return an error.



Compiling Patterns

Building a Database

Hyperscan 컴파일러 API는 정규표현식을 입력받아 그것들을 스캔 작업시에 사용되는 컴파일된 패턴 데이터베이스 형태로 변환합니다.

The Hyperscan compiler API accepts regular expressions and converts them into a compiled pattern database that can then be used to scan data.


API에서는 정규표현식을 데이터베이스화하기 위한 3가지 형태의 함수를 제공하고 있습니다.

The API provides three functions that compile regular expressions into databases:


  1. hs_compile(): 단일 정규표현식을 패턴 데이터베이스로 컴파일합니다.
  2. hs_compile_multi(): 정규표현식의 배열(정규표현식의 집합)을 패턴 데이터베이스로 컴파일합니다. 지원하는 모든 패턴들이 매칭에 성공하는 경우에 반환되는 사용자 정의 구분자(id)를 가지고 동시에 스캔될 것입니다.
  3. hs_compile_ext_multi(): 위 함수와 마찬가지로 정규표현식의 배열(정규표현식의 집합)을 패턴 데이터베이스로 컴파일하며, 각각의 표현식에 대해 확장된 파라미터가 명시되도록 허용합니다.
  1. hs_compile(): compiles a single expression into a pattern database.
  2. hs_compile_multi(): compiles an array of expressions into a pattern database. All of the supplied patterns will be scanned for concurrently at scan time, with user-supplied identifiers returned when they match.
  3. hs_compile_ext_multi(): compiles an array of expressions as above, but allows Extended Parameters to be specified for each expression.

컴파일 작업은 Hyperscan 라이브러리가 주어진 패턴들을 분석할 수 있도록 해주고, 런타임 시에 계산했다면 비용이 굉장히 클 수 있는 이러한 패턴들을 어떻게하면 최적화된 방식으로 스캔할 수 있을지를 미리 결정하도록 해줍니다.

Compilation allows the Hyperscan library to analyze the given pattern(s) and pre-determine how to scan for these patterns in an optimized fashion that would be far too expensive to compute at run-time.


표현식들을 컴파일하고자 할때는, 컴파일된 패턴들의 결과가 스트리밍 모드에 사용될것인지 블록 또는 벡터 모드에서 사용될 것인지 여부를 결정해야합니다.

When compiling expressions, a decision needs to be made whether the resulting compiled patterns are to be used in a streaming, block or vectored mode:


  • 스트리밍 모드: 스캔하려는 대상이 연속적인 스트림이며 이를 한번에 스캔할 수는 없습니다; 데이터의 블록이 순차적으로 스캔되며 스트림 내 여러 블록들에서 매칭이 발생할 수 있습니다. 스트리밍 모드에서 각각의 스트림은 스캔 호출 간의 스트림 상태를 저장하기 위한 메모리 블록을 필요로 합니다.
  • 블록 모드: 스캔 대상이 개별적이고 인접한 블록이며 이 블록은 한번의 호출로 스캔될 수 있으며 상태값 저장이 필요하지 않습니다.
  • 벡터 모드: 스캔 대상이 한번에 처리가 가능한 인접하지 않은 블록의 리스트로 구성되어있습니다. 블록 모드와 마찬가지로 상태값 저장은 필요하지 않습니다.
  • Streaming mode: the target data to be scanned is a continuous stream, not all of which is available at once; blocks of data are scanned in sequence and matches may span multiple blocks in a stream. In streaming mode, each stream requires a block of memory to store its state between scan calls.
  • Block mode: the target data is a discrete, contiguous block which can be scanned in one call and does not require state to be retained.
  • Vectored mode: the target data consists of a list of non-contiguous blocks that are available all at once. As for block mode, no retention of state is required.

스트리밍 모드에 사용되는 패턴들을 컴파일하기 위해서는 hs_compile() 함수의 모드 파라미터 값을 HS_MODE_STREAM으로 설정해야합니다; 이와 동일하게, 블록 모드는 HS_MODE_BLCOK, 벡터 모드에서는 HS_MODE_VECTORED로 설정해야합니다. 하나의 모드로 컴파일된 패턴 데이터베이스는 오직 그 모드에서만 사용할 수 있습니다. 패턴 데이터베이스를 컴파일하기 위해 사용된 Hyperscan 버전과 스캔을 위한 Hyperscan 버전은 반드시 일치해야합니다.

To compile patterns to be used in streaming mode, the mode parameter of hs_compile() must be set to HS_MODE_STREAM; similarly, block mode requires the use of HS_MODE_BLOCK and vectored mode requires the use of HS_MODE_VECTORED. A pattern database compiled for one mode (streaming, block or vectored) can only be used in that mode. The version of Hyperscan used to produce a compiled pattern database must match the version of Hyperscan used to scan with it.


Pattern Support

Hyperscan은 PCRE 라이브러리(“libpcre”)에서 사용되는 패턴 문법(https://www.pcre.org 참조)을 지원합니다. 하지만 libpcre에서 사용가능한 모든 구조들을 지원하는 것은 아닙니다. 지원하지 않는 구조들을 사용하는 경우 컴파일 에러를 발생시킬 것입니다.

Hyperscan supports the pattern syntax used by the PCRE library (“libpcre”), described at https://www.pcre.org. However, not all constructs available in libpcre are supported. The use of unsupported constructs will result in compilation errors.


PCRE 8.41 또는 그 상위 버전을 사용해야만 Hyperscan의 PCRE 라이브러리 문법 분석이 유효합니다.

The version of PCRE used to validate Hyperscan’s interpretation of this syntax is 8.41 or above.


Supported Constructs

지원하는 정규표현식 구조들은 해당 링크를 통해 확인가능하며, 아래 2가지 정보를 참고하시기 바랍니다.

임의 표현식의 매우 큰 반복 횟수를 갖는 경계가 있는 반복 한정사(예를 들어, ([a-z]|bc*d|xy?z){1000,5000})는 패턴 컴파일 타임에 “Pattern too large” 에러를 발생시킬 것입니다.

Bounded-repeat quantifiers with large repeat counts of arbitrary expressions (e.g. ([a-z]|bc*d|xy?z){1000,5000}) will result in a “Pattern too large” error at pattern compile time.

매칭의 시작 지점을 추출하는 옵션 플래그값인 HS_FLAG_SOM_LEFTMOST를 사용하여 컴파일하는 경우에는 모든 패턴이 정상적으로 컴파일되지 않을 수 있습니다. 해당 플래그 값을 지원하는 패턴들은 Hyperscan에 의해 정상적으로 컴파일되는 패턴들의 일부입니다; 주목할점은, 매칭의 시작 지점을 추출하는 옵션을 사용하지 않고 Hyperscan 컴파일이 가능한 대다수의 경계가 있는 반복 한정사 형태들은 해당 옵션을 사용하는 경우에는 컴파일되지 않을 수 있습니다. (반복 한정사를 사용하는 패턴들의 경우에는 컴파일 시 SOM값 사용에 주의해야함)

At this time, not all patterns can be successfully compiled with the HS_FLAG_SOM_LEFTMOST flag, which enables per-pattern support for Start of Match. The patterns that support this flag are a subset of patterns that can be successfully compiled with Hyperscan; notably, many bounded repeat forms that can be compiled with Hyperscan without the Start of Match flag enabled cannot be compiled with the flag enabled.


Semantics

Hyperscan은 기본적으로 libpcre 문법을 따르지만, 약간은 다른 문법를 제공합니다. libpcre 문법과의 주요한 차이는 스트리밍과 다중 동시(multiple simultaneous) 패턴 매칭의 요구 사항들에 의해 발생한 것입니다.

While Hyperscan follows libpcre syntax, it provides different semantics. The major departures from libpcre semantics are motivated by the requirements of streaming and multiple simultaneous pattern matching.


libpcre 문법과 주요한 차이는 아래와 같습니다.

The major departures from libpcre semantics are:


  1. 다중 패턴 매칭: Hyperscan은 패턴 매칭이 몇몇 패턴에 대해 동시에 분석되도록 허용합니다. 이것은 libpcre에서 |(파이프)를 통해 패턴들을 구분하는 것과는 다릅니다.
  2. 순서를 보장하지 않음: Hyperscan에서 제공하는 다중 매치는 순서를 보장하지 않습니다.
  3. 종료 오프셋만 제공: Hyperscan의 기본 동작은 매칭의 종료 오프셋만을 알려주도록 되어있습니다. 시작 오프셋 값의 사용 여부는 패턴 컴파일 타임에 표현식 마다 특정 플래그값(HS_FLAG_SOM_LEFTMOS)을 통해 설정할 수 있습니다. Start of Match 단락에서 자세한 내용을 살펴볼 수 있습니다.
  4. “모든 매칭”에 대한 리포트: 표현식 fooxyzbarbar에 대해 foo.*bar 패턴을 스캔하는 경우 Hyperscan은 2가지 매칭 결과(fooxyzbar와 fooxyzbarbar의 끝지점과 일치하는 시점에)를 반환할 것입니다. 이와 대조적으로 기본적인 libpcre 문법에서는 오로지 하나의 매칭 결과만을 반환하게 됩니다. (greedy semantics을 사용하는 경우라면 fooxyzbarbar를 non-greedy semantics을 사용하는 경우라면 fooxyzbar를) 이것은 greedy와 non-greedy semantics간의 전환 과정이 Hyperscan에서는 존재하지 않는다는 것을 의미합니다.
  1. Multiple pattern matching: Hyperscan allows matches to be reported for several patterns simultaneously. This is not equivalent to separating the patterns by | in libpcre, which evaluates alternations left-to-right.
  2. Lack of ordering: the multiple matches that Hyperscan produces are not guaranteed to be ordered, although they will always fall within the bounds of the current scan.
  3. End offsets only: Hyperscan’s default behaviour is only to report the end offset of a match. Reporting of the start offset can be enabled with per-expression flags at pattern compile time. See Start of Match for details.
  4. “All matches” reported: scanning /foo.*bar/ against fooxyzbarbar will return two matches from Hyperscan – at the points corresponding to the ends of fooxyzbar and fooxyzbarbar. In contrast, libpcre semantics by default would report only one match at fooxyzbarbar (greedy semantics) or, if non-greedy semantics were switched on, one match at fooxyzbar. This means that switching between greedy and non-greedy semantics is a no-op in Hyperscan.

Start of Match(SOM)

기본적으로 Hyperscan은 매칭 콜백 함수(패턴 매칭이 발생하는 경우 어플리케이션에게 호출 결과를 알려주는 콜백 함수)가 호출될 때 매칭의 종료 오프셋만을 제공할 것입니다. 만약 HS_FLAG_SOM_LEFTMOST 플래그값을 특정 패턴에 적용한다면 동일한 매칭 결과뿐만 아니라 종료 오프셋에 부합하는 가장 왼쪽의 시작 오프셋도 제공할 것입니다.

In standard operation, Hyperscan will only provide the end offset of a match when the match callback is called. If the HS_FLAG_SOM_LEFTMOST flag is specified for a particular pattern, then the same set of matches is returned, but each match will also provide the leftmost possible start offset corresponding to its end offset.


SOM(Start of Match) 플래그의 사용은 몇가지 트레이드오프와 제한들을 수반합니다.

Using the SOM flag entails a number of trade-offs and limitations:


  • 지원하는 패턴의 감소: 많은 패턴에 대해, SOM을 추적하는 과정은 복잡하며 Hyperscan의 패턴 컴파일 과정에서 “Pattern too large” 에러를 발생시킬 수 있습니다. (SOM 플래그를 사용하지 않으면 지원하는 패턴이라할지라도)
  • 증가된 스트림 상태: 스캔 시점에 상태 공간은 SOM 오프셋값을 추적하는데 필요하며, 스트리밍 모드 사용 시 해당 공간에는 지속적인 스트림 상태 정보가 저장되어야합니다. 이와 같은 이유로 SOM은 패턴 매칭 시 요구되는 스트림 상태를 증가시킬 것입니다.
  • 성능 오버헤드: 일반적으로 SOM을 추적하는 것과 관련된 성능 비용이 존재합니다.
  • 양립할 수 없는 특성: 몇가지 다른 Hyperscan 패턴 플래그(HS_FLAG_SINGLEMATCH나 HS_FLAG_PREFILTER)들과 SOM은 동시에 사용될 수 없습니다. 이들을 HS_FLAG_SOM_LEFTMOST와 함께 사용하는 경우에는 컴파일 에러를 발생시킬 것입니다.
  • Reduced pattern support: For many patterns, tracking SOM is complex and can result in Hyperscan failing to compile a pattern with a “Pattern too large” error, even if the pattern is supported in normal operation.
  • Increased stream state: At scan time, state space is required to track potential SOM offsets, and this must be stored in persistent stream state in streaming mode. Accordingly, SOM will generally increase the stream state required to match a pattern.
  • Performance overhead: Similarly, there is generally a performance cost associated with tracking SOM.
  • Incompatible features: Some other Hyperscan pattern flags (such as HS_FLAG_SINGLEMATCH and HS_FLAG_PREFILTER) can not be used in combination with SOM. Specifying them together with HS_FLAG_SOM_LEFTMOST will result in a compilation error.

스트리밍 모드에서는 SOM에 의해 전달되는 정밀성의 정도를 SOM horizon 플래그들을 통해 조절할 수 있습니다. 이 플래그들은 Hyperscan이 종료 오프셋의 특정 길이 내에서 정확한 SOM 정보를 전달하도록 하며, 그렇지않은 경우에는 HS_OFFSET_PAST_HORIZON의 특별한 시작 오프셋을 반환하도록 합니다.

In streaming mode, the amount of precision delivered by SOM can be controlled with the SOM horizon flags. These instruct Hyperscan to deliver accurate SOM information within a certain distance of the end offset, and return a special start offset of HS_OFFSET_PAST_HORIZON otherwise. Specifying a small or medium SOM horizon will usually reduce the stream state required for a given database.

스트리밍 모드에서 매칭 결과로 반환되는 시작 오프셋은 현재 스캔중인 블록 이전의 스트림 내 한 지점을 가리킵니다. Hyperscan은 이전 블록들을 평가하는 도구를 제공하지 않습니다; 만약 이전 데이터에 대한 검사가 필요하다면 어플리케이션 자체적으로 그 데이터들을 저장해야만 합니다.

In streaming mode, the start offset returned for a match may refer to a point in the stream before the current block being scanned. Hyperscan provides no facility for accessing earlier blocks; if the calling application needs to inspect historical data, then it must store it itself.




Scanning for Patterns

Hyperscan은 3가지 다른 스캐닝 모드를 제공합니다. 각각의 모드들은 hs_scan으로 시작하는 그들만의 스캐닝 함수를 갖고 있습니다. 추가적으로 스트리밍 모드에는 스트림 상태를 관리하는 몇가지 다른 API 함수들이 존재합니다.

Hyperscan provides three different scanning modes, each with its own scan function beginning with hs_scan. In addition, streaming mode has a number of other API functions for managing stream state.


Handling Matches

매칭이 발생한 경우 모든 스캐닝 함수들은 사용자가 정의한 콜백 함수를 호출할 것입니다. 이 콜백 함수는 아래와 같은 반환 값과 매개변수를 갖습니다:

All of these functions will call a user-supplied callback function when a match is found. This function has the following signature:

1
typedef int (*match_event_handler)(unsigned int id, unsigned long long from, unsigned long long to, unsigned int flags, void *context)

매개변수 id에는 매칭된 표현에대해 컴파일 타임에 입력됐던 id값이 저장되며, 매개변수 to에는 매칭의 종료 오프셋이 저장될 것입니다. 만약 해당 패턴에 SOM이 요청됐다면, 매개변수 from에는 매칭의 가장 왼쪽의 시작 오프셋이 저장될 것입니다.

The id argument will be set to the identifier for the matching expression provided at compile time, and the to argument will be set to the end-offset of the match. If SOM was requested for the pattern (see Start of Match), the from argument will be set to the leftmost possible start-offset for the match.


콜백 함수에는 0이 아닌 값을 반환하여 스캐닝 작업을 중지할 수 있는 기능이 있습니다.

The match callback function has the capability to halt scanning by returning a non-zero value.


콜백 함수에 대한 더 많은 정보는 match_event_handler을 참조하시기 바랍니다.

See match_event_handler for more information.


Streaming Mode

일단은 블록모드부터😁
링크 참조


Block Mode

블록 모드 API는 hs_scan() 함수 하나로 구성되어 있습니다. 해당 함수는 컴파일된 패턴을 사용하여 타겟 데이터내의 매치 정보를 추출하고, 함수 포인터 콜백을 사용하여 어플리케이션과 통신합니다.

The block mode runtime API consists of a single function: hs_scan(). Using the compiled patterns this function identifies matches in the target data, using a function pointer callback to communicate with the application.

hs_scan() 함수는 블록 모드에서는 스트림과 관련된 오버레드를 발생시키지 않는 다는 점만 제외하면 hs_open_stream() → hs_scan_stream() → hs_close_stream()의 호출 과정과 동일합니다.

This single hs_scan() function is essentially equivalent to calling hs_open_stream(), making a single call to hs_scan_stream(), and then hs_close_stream(), except that block mode operation does not incur all the stream related overhead.


Vectored Mode

일단은 블록모드부터😁
링크 참조


Scratch Space

데이터를 스캐닝하는 동안 Hyperscan은 그때 그때 생성되는 내부 데이터를 저장하기 위한 용도로 임시 메모리 공간의 일부를 필요로합니다. 이 메모리 공간이 불운하게도 스택에 올라가기에는 너무 크고, 특히나 임베디드 어플리케이션의 경우에, 동적으로 할당하기에는 비용이 너무나 큽니다. 그래서 미리 할당되는 공간인 “스크래치” 공간이 스캐닝 함수에 제공되어야만 합니다.

While scanning data, Hyperscan needs a small amount of temporary memory to store on-the-fly internal data. This amount is unfortunately too large to fit on the stack, particularly for embedded applications, and allocating memory dynamically is too expensive, so a pre-allocated “scratch” space must be provided to the scanning functions.


hs_alloc_scratch() 함수는 주어진 데이터베이스를 지원하기 위해 충분히 큰 스크래치 공간을 할당합니다. 만약 어플리케이션이 다중 데이터베이스를 사용하는 경우라면, 오직 하나의 스크래치 영역만이 필요합니다: 이 경우, 각각의 데이터베이스마다 (동일한 스크래치 포인터로) hs_alloc_scratch()함수를 호출하는 것은 주어진 데이터베이스라면 어떠한 것이든지 스캐닝을 지원하기 위한 충분한 스크래치 공간을 보장합니다.

The function hs_alloc_scratch() allocates a large enough region of scratch space to support a given database. If the application uses multiple databases, only a single scratch region is necessary: in this case, calling hs_alloc_scratch() on each database (with the same scratch pointer) will ensure that the scratch space is large enough to support scanning against any of the given databases.


Hyperscan 라이브러리는 re-entrant(여러 쓰레드가 코드를 동시에 수행할 수 있고, 그런 경우에도 실행 결과의 correctness가 보장되는 것) 하지만, 스크래치 공간의 사용은 그렇지 않습니다. 예를 들어, 구성 상 재귀적이고 중첩되는 스캐닝 동작이 필요로 하다면, 컨텍스트 마다의 스크래치 공간이 요구됩니다.

While the Hyperscan library is re-entrant, the use of scratch spaces is not. For example, if by design it is deemed necessary to run recursive or nested scanning (say, from the match callback function), then an additional scratch space is required for that context.

재귀적인 스캐닝이 없는 경우라면, 쓰레드 하나 당 오로지 하나의 스크래치 공간만이 필요하며 이 공간은 데이터 스캐닝이 시작되기 전에 할당될 수 있습니다.

In the absence of recursive scanning, only one such space is required per thread and can (and indeed should) be allocated before data scanning is to commence.

하나의 “main” 쓰레드에서 표현식들의 집합이 컴파일되고 데이터가 다중 “worker” 쓰레드에 의해 스캐닝되는 상황에서는, hs_clone_scratch()라는 편리한 함수가 이미 존재하는 스크래치 공간의 복사본이 각각의 쓰레드들에게 할당될 수 있도록해줍니다.

In a scenario where a set of expressions are compiled by a single “main” thread and data will be scanned by multiple “worker” threads, the convenience function hs_clone_scratch() allows multiple copies of an existing scratch space to be made for each thread (rather than forcing the caller to pass all the compiled databases through hs_alloc_scratch() multiple times).


예를 들어

For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
hs_error_t err;
hs_scratch_t *scratch_prototype = NULL;
err = hs_alloc_scratch(db, &scratch_prototype);
if (err != HS_SUCCESS) {
printf("hs_alloc_scratch failed!");
exit(1);
}

hs_scratch_t *scratch_thread1 = NULL;
hs_scratch_t *scratch_thread2 = NULL;

// 위에서 할당한 scratch_prototype 공간을 복사(clone)해서 scratch_thread1에서도 사용
err = hs_clone_scratch(scratch_prototype, &scratch_thread1);
if (err != HS_SUCCESS) {
printf("hs_clone_scratch failed!");
exit(1);
}

// 위에서 할당한 scratch_prototype 공간을 복사(clone)해서 scratch_thread2에서도 사용
err = hs_clone_scratch(scratch_prototype, &scratch_thread2);
if (err != HS_SUCCESS) {
printf("hs_clone_scratch failed!");
exit(1);
}

hs_free_scratch(scratch_prototype);

/* Now two threads can both scan against database db, each with its own scratch space. */


해당 게시글에서 발생한 오탈자나 잘못된 내용에 대한 정정 댓글 격하게 환영합니다😎

Reference