A device detection library that is used natively or by 51Degrees products

Hash/ReloadFromFile.c

Reload from file example of using 51Degrees device detection.

Reload from file example of using 51Degrees device detection.This example shows how to:

  1. Only maintain a reference to the fiftyoneDegreesResourceManager and use the reference to access dataset.
  2. Use the fiftyoneDegreesHashReloadManagerFromOriginalFile function to reload the dataset from the same location and with the same set of properties.
  3. Retrieve a results instance from the data set and release it when done with detecting current User-Agent.
  4. Use the reload functionality in a single threaded environment.
  5. Use the reload functionality in a multi threaded environment.

This example illustrates how to use a single reference to the resource manager to use device detection and invoke the reload functionality instead of maintaining a reference to the dataset directly.

The fiftyoneDegreesHashReloadManagerFromOriginalFile function requires an existing resource with the initialized dataset. Function reloads the dataset from the same location and with the same parameters as the original dataset.

Please keep in mind that even if the current dataset was constructed with all available properties this does not guarantee that the new dataset will be initialized with the same set of properties. If the new data file contains properties that were not part of the original data file, the new extra property(ies) will not be initialized. If the new data file does not contain one or more property that were previously available, then these property(ies) will not be initialized.

Each successful data file reload should be accompanied by the integrity check to verify that the properties you want have indeed been loaded. This can be achieved by simply comparing the number of properties before and after the reload as the number can not go up but it can go down.

The reload functionality works both with the single threaded as well as the multi threaded modes. To try the reload functionality in single threaded mode build with FIFTYONE_DEGREES_NO_THREADING defined. Or build without FIFTYONE_DEGREES_NO_THREADING for multi threaded example.

In a single threaded environment the reload function is executed as part of the normal flow of the program execution and will prevent any other actions until the reload is complete. The reload itself takes less than half a second even for Enterprise dataset. For more information see: /Support/Documentation/APIs/C-V32/Benchmarks?utm_source=code&utm_medium=example&utm_campaign=51degrees-cxx&utm_content=examples-c-hash-reloadfromfile.c&utm_term=header

/* *********************************************************************
* This Original Work is copyright of 51 Degrees Mobile Experts Limited.
* Copyright 2026 51 Degrees Mobile Experts Limited, Davidson House,
* Forbury Square, Reading, Berkshire, United Kingdom RG1 3EU.
*
* This Original Work is licensed under the European Union Public Licence
* (EUPL) v.1.2 and is subject to its terms as set out below.
*
* If a copy of the EUPL was not distributed with this file, You can obtain
* one at https://opensource.org/licenses/EUPL-1.2.
*
* The 'Compatible Licences' set out in the Appendix to the EUPL (as may be
* amended by the European Commission) shall be deemed incompatible for
* the purposes of the Work and the provisions of the compatibility
* clause in Article 5 of the EUPL shall not apply.
*
* If using the Work as, or as part of, a network application, by
* including the attribution notice(s) required under Article 5 of the EUPL
* in the end user terms of the application under an appropriate heading,
* such notice(s) shall fulfill the requirements of that article.
* ********************************************************************* */
#include <stdio.h>
#include <stdlib.h>
#ifdef _MSC_VER
#pragma warning (push)
#pragma warning (disable: 5105)
#include <windows.h>
#pragma warning (default: 5105)
#pragma warning (pop)
#else
#include <unistd.h>
#endif
// Include ExmapleBase.h before others as it includes Windows 'crtdbg.h'
// which requires to be included before 'malloc.h'.
#include "ExampleBase.h"
#include "../../../../src/common/textfile.h"
#include "../../../../src/dd/hash/hash.h"
#include "../../../../src/dd/hash/fiftyone.h"
#define THREAD_COUNT 4
static const char *dataDir = "data/device-detection";
static const char *dataFileName = "51Degrees-LiteV4.1.hash";
static const char *userAgentFileName = "20000 User Agents.csv";
// Returned by main. Set to 1 when the data file cannot be used.
static int exitCode = 0;
// #define CONFIG fiftyoneDegreesHashInMemoryConfig
// #define CONFIG fiftyoneDegreesHashHighPerformanceConfig
// #define CONFIG fiftyoneDegreesHashLowMemoryConfig
#define CONFIG fiftyoneDegreesHashBalancedConfig
// #define CONFIG fiftyoneDegreesHashBalancedTempConfig
typedef struct shared_state_t {
ResourceManager *manager;
const char *userAgentFilePath;
volatile long threadsFinished;
THREAD threads[THREAD_COUNT];
typedef struct thread_state_t {
ResourceManager *manager;
int hashCode;
static unsigned long generateHash(unsigned char *value) {
unsigned long hashCode = 5381;
while (*value != '\0') {
hashCode = ((hashCode << 5) + hashCode) + (unsigned long)*value;
value++;
}
return hashCode;
}
static unsigned long getHashCode(ResultsHash *results) {
Item *valueItem;
unsigned long hashCode = 0;
uint32_t requiredPropertyIndex;
const char *valueName;
DataSetHash *dataSet = (DataSetHash*)results->b.b.dataSet;
for (requiredPropertyIndex = 0;
requiredPropertyIndex < PropertiesGetRequiredPropertyCount(
dataSet->b.b.available);
requiredPropertyIndex++) {
results,
requiredPropertyIndex,
exception) == true) {
valueItem = ResultsHashGetValues(
results,
requiredPropertyIndex,
exception);
valueName = STRING(valueItem->data.ptr);
hashCode ^= generateHash((unsigned char*)(valueName));
}
}
return hashCode;
}
static void executeTest(const char *userAgent, void *state) {
threadState *thread = (threadState*)state;
ResultsHash *results = ResultsHashCreate(thread->manager, 0);
"User-Agent",
userAgent);
ResultsHashFromEvidence(results, evidence, exception);
thread->hashCode ^= getHashCode(results);
ResultsHashFree(results);
}
static void runRequestsSingle(sharedState *state) {
char userAgent[500] = "";
sharedState *shared = (sharedState*)state;
threadState thread;
thread.hashCode = 0;
thread.manager = shared->manager;
userAgent,
sizeof(userAgent),
&thread,
executeTest);
printf("Finished with hash code '%i'\r\n", thread.hashCode);
}
static void runRequestsMulti(void *state) {
sharedState *shared = (sharedState*)state;
runRequestsSingle(shared);
}
static void startThreads(sharedState *state) {
int thread;
for (thread = 0; thread < THREAD_COUNT; thread++) {
state->threads[thread],
(THREAD_ROUTINE)&runRequestsMulti,
state);
}
}
static void joinThreads(sharedState *state) {
int thread;
for (thread = 0; thread < THREAD_COUNT; thread++) {
THREAD_JOIN(state->threads[thread]);
THREAD_CLOSE(state->threads[thread]);
}
}
static void reportStatus(
StatusCode status,
const char* fileName) {
const char *message = StatusGetMessage(status, fileName);
printf("%s\n", message);
Free((void*)message);
}
static void run(
ResourceManager *manager,
const char *userAgentFilePath) {
StatusCode status;
int numberOfReloads = 0;
int numberOfReloadFails = 0;
sharedState state;
state.manager = manager;
state.userAgentFilePath = userAgentFilePath;
state.threadsFinished = 0;
printf("** Multi Threaded Reload Example **\r\n");
startThreads(&state);
while (state.threadsFinished < THREAD_COUNT) {
manager,
exception);
if (status == SUCCESS) {
numberOfReloads++;
}
else {
numberOfReloadFails++;
}
#ifdef _MSC_VER
Sleep(1000); // milliseconds
#else
usleep(1000000); // microseconds
#endif
}
joinThreads(&state);
}
else {
printf("** Single Threaded Reload Example **\r\n");
runRequestsSingle(&state);
manager,
exception);
if (status == SUCCESS) {
numberOfReloads++;
}
else {
numberOfReloadFails++;
}
runRequestsSingle(&state);
}
// Report the number of reloads.
printf("Reloaded '%i' times.\r\n", numberOfReloads);
printf("Failed to reload '%i' times.\r\n", numberOfReloadFails);
printf("Program execution complete. Press Return to exit.");
}
void fiftyoneDegreesHashReloadFromFileRun(
const char *dataFilePath,
const char *userAgentFilePath,
const char *requiredProperties,
ConfigHash config) {
// Set the required properties to the string provided in the arguments.
// Set the required properties for hashing each test thread.
reqProps.string = requiredProperties;
// Set concurrency to ensure sufficient shared resources available.
config.nodes.concurrency =
config.strings.concurrency = THREAD_COUNT;
// Set the device detection specific parameters to avoid checking for
// upper case prefixed headers and tracking the matched User-Agent
// characters.
config.b.b.usesUpperPrefixedHeaders = false;
config.b.updateMatchedUserAgent = false;
ResourceManager manager;
&manager,
&config,
&reqProps,
dataFilePath,
exception);
// Free the memory used for the required properties if allocated.
if (requiredProperties != reqProps.string) {
free((void*)reqProps.string);
}
if (status != SUCCESS) {
reportStatus(status, dataFilePath);
exitCode = 1;
}
else {
// Run the performance tests.
run(&manager, userAgentFilePath);
// Free the memory used by the data set.
}
}
void fiftyoneDegreesExampleCReloadFromFileRun(ExampleParameters *params) {
// Call the actual function.
fiftyoneDegreesHashReloadFromFileRun(
params->dataFilePath,
params->evidenceFilePath,
params->propertiesString,
*params->config);
}
#ifndef TEST
int main(int argc, char* argv[]) {
StatusCode status = SUCCESS;
char dataFilePath[FILE_MAX_PATH];
char userAgentFilePath[FILE_MAX_PATH];
if (argc > 1) {
strcpy(dataFilePath, argv[1]);
}
else {
status = fiftyoneDegreesExampleGetFilePath(
dataDir,
dataFileName,
dataFilePath,
sizeof(dataFilePath));
}
if (status != SUCCESS) {
reportStatus(status, dataFileName);
fgetc(stdin);
return 1;
}
if (argc > 2) {
strcpy(userAgentFilePath, argv[2]);
}
else {
status = fiftyoneDegreesExampleGetFilePath(
dataDir,
userAgentFileName,
userAgentFilePath,
sizeof(userAgentFilePath));
}
if (status != SUCCESS) {
reportStatus(status, userAgentFilePath);
fgetc(stdin);
return 1;
}
ConfigHash config = CONFIG;
ExampleParameters params;
params.dataFilePath = dataFilePath;
params.evidenceFilePath = userAgentFilePath;
params.propertiesString =
argc > 3 ? argv[3] : "IsMobile,BrowserName,DeviceType";
params.config = &config;
// Run the example
fiftyoneDegreesExampleMemCheck(
&params,
fiftyoneDegreesExampleCReloadFromFileRun);
// Wait for a character to be pressed.
fgetc(stdin);
return exitCode;
}
#endif
@ FIFTYONE_DEGREES_EVIDENCE_HTTP_HEADER_STRING
An HTTP header value.
Definition evidence.h:139
#define ResultsHashFromEvidence
Synonym for fiftyoneDegreesResultsHashFromEvidence function.
Definition dd/hash/fiftyone.h:70
#define ResultsHashGetValues
Synonym for fiftyoneDegreesResultsHashGetValues function.
Definition dd/hash/fiftyone.h:58
fiftyoneDegreesConfigHash ConfigHash
Synonym for fiftyoneDegreesConfigHash type.
Definition dd/hash/fiftyone.h:51
fiftyoneDegreesResultsHash ResultsHash
Synonym for fiftyoneDegreesResultsHash type.
Definition dd/hash/fiftyone.h:50
fiftyoneDegreesDataSetHash DataSetHash
Synonym for fiftyoneDegreesDataSetHash type.
Definition dd/hash/fiftyone.h:48
#define ResultsHashCreate(manager, overridesCapacity)
Two argument convenience form of fiftyoneDegreesResultsHashCreate that injects the deprecated userAge...
Definition dd/hash/fiftyone.h:66
#define ResultsHashGetHasValues
Synonym for fiftyoneDegreesResultsHashGetHasValues function.
Definition dd/hash/fiftyone.h:59
#define ResultsHashFree
Synonym for fiftyoneDegreesResultsHashFree function.
Definition dd/hash/fiftyone.h:67
#define HashInitManagerFromFile
Synonym for fiftyoneDegreesHashInitManagerFromFile function.
Definition dd/hash/fiftyone.h:75
#define HashReloadManagerFromOriginalFile
Synonym for fiftyoneDegreesHashReloadManagerFromOriginalFile function.
Definition dd/hash/fiftyone.h:79
#define ThreadingGetIsThreadSafe
Synonym for fiftyoneDegreesThreadingGetIsThreadSafe function.
Definition common/fiftyone.h:339
#define STRING
Synonym for FIFTYONE_DEGREES_STRING macro.
Definition common/fiftyone.h:448
#define EXCEPTION_THROW
Synonym for FIFTYONE_DEGREES_EXCEPTION_THROW macro.
Definition common/fiftyone.h:446
fiftyoneDegreesEvidenceKeyValuePairArray EvidenceKeyValuePairArray
Synonym for fiftyoneDegreesEvidenceKeyValuePairArray type.
Definition common/fiftyone.h:172
#define PropertiesDefault
Synonym for fiftyoneDegreesPropertiesDefault function.
Definition common/fiftyone.h:268
#define EXCEPTION_CREATE
Synonym for FIFTYONE_DEGREES_EXCEPTION_CREATE macro.
Definition common/fiftyone.h:443
#define THREAD
Synonym for FIFTYONE_DEGREES_THREAD macro.
Definition common/fiftyone.h:461
#define StatusGetMessage
Synonym for fiftyoneDegreesStatusGetMessage function.
Definition common/fiftyone.h:293
#define TextFileIterate
Synonym for fiftyoneDegreesTextFileIterate function.
Definition common/fiftyone.h:348
#define EvidenceCreate
Synonym for fiftyoneDegreesEvidenceCreate function.
Definition common/fiftyone.h:240
#define INTERLOCK_INC
Synonym for FIFTYONE_DEGREES_INTERLOCK_INC macro.
Definition common/fiftyone.h:462
fiftyoneDegreesCollectionItem Item
Synonym for fiftyoneDegreesCollectionItem type.
Definition common/fiftyone.h:105
#define PropertiesGetRequiredPropertyCount
Synonym for fiftyoneDegreesPropertiesGetRequiredPropertyCount function.
Definition common/fiftyone.h:327
fiftyoneDegreesStatusCode StatusCode
Synonym for fiftyoneDegreesStatusCode type.
Definition common/fiftyone.h:134
#define THREAD_JOIN
Synonym for FIFTYONE_DEGREES_THREAD_JOIN macro.
Definition common/fiftyone.h:454
#define EvidenceAddString
Synonym for fiftyoneDegreesEvidenceAddString function.
Definition common/fiftyone.h:324
#define THREAD_CREATE
Synonym for FIFTYONE_DEGREES_THREAD_CREATE macro.
Definition common/fiftyone.h:451
#define SUCCESS
Synonym for FIFTYONE_DEGREES_STATUS_SUCCESS status code.
Definition common/fiftyone.h:478
#define EXCEPTION_CLEAR
Synonym for FIFTYONE_DEGREES_EXCEPTION_CLEAR macro.
Definition common/fiftyone.h:442
#define EvidenceFree
Synonym for fiftyoneDegreesEvidenceFree function.
Definition common/fiftyone.h:241
#define THREAD_ROUTINE
Synonym for FIFTYONE_DEGREES_THREAD_ROUTINE macro.
Definition common/fiftyone.h:455
#define ResourceManagerFree
Synonym for fiftyoneDegreesResourceManagerFree function.
Definition common/fiftyone.h:310
fiftyoneDegreesResourceManager ResourceManager
Synonym for fiftyoneDegreesResourceManager type.
Definition common/fiftyone.h:137
#define THREAD_CLOSE
Synonym for FIFTYONE_DEGREES_THREAD_CLOSE macro.
Definition common/fiftyone.h:452
fiftyoneDegreesPropertiesRequired PropertiesRequired
Synonym for fiftyoneDegreesPropertiesRequired type.
Definition common/fiftyone.h:135
#define Free
Synonym for fiftyoneDegreesFree function.
Definition common/fiftyone.h:265
#define FILE_MAX_PATH
Synonym for FIFTYONE_DEGREES_FILE_MAX_PATH macro.
Definition common/fiftyone.h:450
Definition GettingStarted.c:67
uint16_t concurrency
Expected number of concurrent requests, 1 or greater.
Definition collection.h:299
bool usesUpperPrefixedHeaders
True if the HTTP header field names MIGHT include the prefix HTTP_.
Definition config.h:56
fiftyoneDegreesConfigBase b
Base structure members.
Definition config-dd.h:53
bool updateMatchedUserAgent
True if the detection should record the matched characters from the target User-Agent.
Definition config-dd.h:54
fiftyoneDegreesCollectionConfig rootNodes
Root nodes collection config.
Definition hash.h:197
fiftyoneDegreesCollectionConfig properties
Properties collection config.
Definition hash.h:193
fiftyoneDegreesCollectionConfig nodes
Nodes collection config.
Definition hash.h:199
fiftyoneDegreesCollectionConfig values
Values collection config.
Definition hash.h:195
fiftyoneDegreesConfigDeviceDetection b
Base configuration.
Definition hash.h:188
fiftyoneDegreesCollectionConfig strings
Strings collection config.
Definition hash.h:189
fiftyoneDegreesCollectionConfig profiles
Profiles collection config.
Definition hash.h:196
fiftyoneDegreesCollectionConfig components
Components collection config.
Definition hash.h:190
fiftyoneDegreesCollectionConfig profileOffsets
Profile offsets collection config.
Definition hash.h:200
const char * string
Separated list of required properties or NULL if all properties are required.
Definition properties.h:234
State containing the states for all threads running in the example.
Definition ReloadFromFile.c:121
const char * userAgentFilePath
Path to the User-Agents to process.
Definition ReloadFromFile.c:124
THREAD threads[THREAD_COUNT]
Pointers to the running threads.
Definition ReloadFromFile.c:127
ResourceManager * manager
Pointer to the manager containing the data set.
Definition ReloadFromFile.c:122
volatile long threadsFinished
Number of threads that have finished their processing.
Definition ReloadFromFile.c:125
State specific to a single thread.
Definition Performance.c:157
ResourceManager * manager
Pointer to the manager containing the data set.
Definition ReloadFromFile.c:134
int hashCode
Running hash code for the processing being carried out.
Definition ReloadFromFile.c:136