Skip to content
This repository has been archived by the owner on Feb 20, 2021. It is now read-only.

Commit

Permalink
Windows port of antirez/3.2.
Browse files Browse the repository at this point in the history
  • Loading branch information
enricogior committed Jun 14, 2016
1 parent 7ca8fba commit 649cd88
Show file tree
Hide file tree
Showing 382 changed files with 76,703 additions and 2,905 deletions.
22 changes: 22 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ redis-sentinel
redis-server
doc-tools
release
bin/
obj/
Debug/
Release/
x64/
misc/*
src/release.h
appendonly.aof
Expand All @@ -27,3 +32,20 @@ deps/lua/src/liblua.a
.make-*
.prerequisites
*.dSYM
*.user
*.exe
*.sdf
*.suo
msvs/ReleasePackagingTool
msvs/ipch
msvs/RedisServer.opensdf
!msvs/RedisWaInst/bin/*
!msvs/RedisWaInst/bin/Inst4WA/*
!msvs/RedisWaInst/bin/RedisPkgBin/*
msvs/RedisWAInst/src/RedisInstBin/
msvs/RedisWAInst/src/RedisInstWA/app.config
msvs/jemalloc
msvs/BuildRelease
msvs/Documentation
tests/tmp/

12 changes: 12 additions & 0 deletions Redis on Windows Release Notes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
MSOpenTech Redis on Windows 3.2 Release Notes
=============================================
--[ Redis on Windows 3.2.000-preview ] Release date: Jun 14 2016

This is a technical preview of Redis on Windows 3.2.
There are still known issues/bugs, in particular there is a bug that prevents
the cluster fail-over functionality to work properly in certain scenarios.
This release SHOULD NOT be used in production.

Changelog:

- Windows port of antirez/3.2.
108 changes: 108 additions & 0 deletions Redis on Windows.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
MSOpenTech’s Redis on Windows
=============================

Redis is an open source, high performance, key-value store. Values may contain strings, hashes, lists, sets and sorted sets. Redis has been developed primarily for UNIX-like operating systems.
Our goal is to provide a version of Redis that runs on Windows with a performance essentially equal to the performance of Redis on an equivalent UNIX machine.
We strive to have a stable, functionally equivalent and comparably performing version of Redis on Windows. We have achieved performance nearly identical to the POSIX version running head-to-head on identical hardware across the network. Aside from feature differences that help Redis take advantage of the Windows infrastructure, our version of Redis should work in most situations with the identical setup and configuration that one would use on a POSIX operating system.

How is Redis on Windows implemented?
====================================

Redis is a C code base that compiles under Visual Studio. Most of the code compiles with only minor changes to the code due to syntactical differences between compilers and low level API differences on Windows. There are a few areas where there are significant differences in how efficient Windows programs operate relative to POSIX programs. We have encapsulated most these differences in a platform specific library. The areas where there are significant differences are:

- Networking APIs

- POSIX File Descriptors

- POSIX fork()

- Logging

- Windows Services API

Networking Differences
----------------------

The Windows networking stack is split between user mode code and kernel mode code. Transitions between user and kernel mode are expensive operations. The POSIX networking APIs on Windows utilize a programming model that incurs significant performance loss due to the kernel/user mode transitions. Efficient Windows networking code instead uses the IO Completion Port model to reduce the impact of this behavior. The APIs used and the programming model for IO Completion is different enough that we were forced to implement a new networking layer in Redis.

File Descriptors
----------------

In a POSIX operating system all data sources (files, pipes, sockets, mail slots, etc.) are referenced in code with a handle called a file descriptor. These are low value integers that increment by one with each successive file descriptor created in a given program. All POSIX APIs that work with file descriptors will function without the programmer having to know what kind of data source a file descriptor represents. On Windows generally each kind of data source has a separate kind of HANDLE. APIs that work with one HANDLE type will not work with another kind of HANDLE. In order to make Redis operate with its assumptions about file descriptor values and data source agnosticism, we implemented a Redis File Descriptor API layer.

fork()
------

The POSIX version of Redis uses the fork() API. There is no equivalent in Windows, and it is an exceedingly difficult API to completely simulate. For most of the uses of fork() we have used Windows specific programming idioms to bypass the need to use a fork()-like API. The one case where we could not do so was with the point-in-time heap snapshot behavior that the Redis persistence model is based on. We tried several different approaches to work around the need for a fork()-like API, but always ran into significant performance penalties and stability issues.

Our current approach is to simulate the point-in-time snapshot behavior aspect of fork() without doing a complete simulation of fork(). We do this with the system-paging file that contains the Redis heap. When a fork() operation is required we do the following:

- Mark every page in the system-paging file with the Copy on Write page protection

- Start a child process and pass it the handle to the system-paging file

- Signal the child to start the AOF or RDB persistence process on the memory shared via the system-paging file

- Wait (asynchronously) for the child process to finish

- Map the changes in the Redis heap that occurred during the fork() operation back into the system-paging file.

The upside with this implementation is that our performance and stability is now on par with the POSIX version of Redis. The down side is that we have a runtime disk space requirement for Redis equal to the size of the Redis memory heap. The disk space requirement defaults to:

- 50% more than the --maxmemory setting if present, otherwise

- The size of physical RAM

We also have a runtime page file commit requirement that varies depending on the amount data in the Redis heap during the quasi-fork operation. The maximum for this is about 3 times the size of the max-memory This is usually not a problem because the default configuration of Windows allows the page file to grow to 3.5 times the size of physical memory. There are scenarios where 3<sup>rd</sup> party programs also compete for system swap space at runtime.

Logging
-------

In addition to file based logging, the POSIX version of Redis supports logging via the syslog facility. The equivalent in Windows is the Event Log. With the recent addition of the Windows Service code we have added support for logging to the Event Log. We have mapped the –syslogxxxx flags for this purpose.

Windows Service
---------------

In version 2.8.9 we are adding support to make Redis operate as a service. See the RedisService.docx file included with the GitHub binary distribution for a description of the service commands available.

Redis on Windows Best Practices
===============================

Binary Distributions
--------------------

The GitHub repository should be considered a work in progress until we release the NuGet and Chocolatey packages and tag the repository at that released version.

For instance, the Windows Service feature has taken many iterations with community input to get right. The initial Windows service code was checked in on April 3. Since that time we have added the following to the service based on community input:

- Self elevation of the Redis executable so that service commands would work from a non-elevated command prompt.

- Service naming so that multiple instances of the Redis service could be installed on one machine.

- Automatically adjusting folder permissions so that when Redis is run under the NETWORK SERVICE account it could modify the files in the installation directory.

- Moved all of the pre-main() error reporting code (service and quasi-fork code) that could write errors to stdout to use the Redis logging code. This allows service initialization errors to reach the Event Log. This required intercepting all of the command line and conf file arguments before main() in order to properly initialize the logging engine. There were several fixes related to the intricacies of how to interpret the arguments passed to Redis.

The final service code has been released as of June 25 in the 2.8.9 Redis-64 packages.

Heap Sizing
-----------

Native heaps are prone to fragmentation. If we are not able to allocate more heap space due to fragmentation Redis will flag the problem and exit. Unlike the POSIX version of Redis, our heap size is constrained by both by disk space and by swap file space. It is important to consider how much data you are expecting to put into Redis, and how much fragmentation you are likely to see in the Redis heap. With very high levels of fragmentation the 50% overhead that –maxmemory imposes may not be enough to prevent running out of heap space. In this case, the use of –maxheap will supersede the –maxmemory default heap setting.

Installation and Maintenance
----------------------------

Since Redis uses system swap space, the most stable configurations will only have Redis running on essentially a virgin operating system install.

Redis is xcopy deployable. There should be no problem upgrading versions by simply copying new binaries over old ones (assuming they are not currently in use).

Service Account
---------------

When using Redis as a Windows service, the default installation configures Redis to run under the system’s NETWORK SERVICE account. There are some environments where another account must be used (perhaps a domain service account). Configuration of this account needs to be done manually at this point with the service control manager. If this is done, it is also important to give read/write/create permission to the folder that the Redis executable is in to this user identity.

How to develop for Redis
========================

You will need a client library for accessing Redis. There are a wide variety of client libraries available as listed at <http://redis.io/clients>.
95 changes: 95 additions & 0 deletions Windows Service Documentation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
Running Redis as a Service
==========================

If you installed Redis using the MSI package, then Redis was already installed as a Windows service. Nothing further to do. If you would like to change its settings, you can update the *redis.windows-service.conf* file and then restart the Redis service (Run -\> services.msc -\> Redis -\> Restart).

During installation of the MSI you can either use the installer’s user interface to update the port that Redis listens at and the firewall exception or run it silently without a UI. The following examples show how to install from the command line:

**default install (port 6379 and firewall exception ON):**

*msiexec /i Redis-x64.msi *

**set port and turn OFF firewall exception:**

*msiexec /i Redis-x64.msi PORT=1234 FIREWALL\_ON=""*

**set port and turn ON firewall exception:**

*msiexec /i Redis-x64.msi PORT=1234 FIREWALL\_ON=1*

**install with no user interface:**

*msiexec /quiet /i Redis-x64.msi*

If you did *not* install Redis using the MSI package, then you still run Redis as a Windows service by following these instructions:

In order to better integrate with the Windows Services model, new command line arguments have been introduced to Redis. These service arguments require an elevated user context in order to connect to the service control manager. If these commands are invoked from a non-elevated context, Redis will attempt to create an elevated context in which to execute these commands. This will cause a User Account Control dialog to be displayed by Windows and may require Administrative user credentials in order to proceed.

Installing the Service
----------------------

*--service-install*

This must be the first argument on the redis-server command line. Arguments after this are passed in the order they occur to Redis when the service is launched. The service will be configured as Autostart and will be launched as "NT AUTHORITY\\NetworkService". Upon successful installation a success message will be displayed and Redis will exit.

This command does not start the service.

For instance:

redis-server --service-install redis.windows.conf --loglevel verbose

Uninstalling the Service
------------------------

*--service-uninstall*

This will remove the Redis service configuration information from the registry. Upon successful uninstallation a success message will be displayed and Redis will exit.

This does command not stop the service.

For instance:

redis-server --service-uninstall

Starting the Service
--------------------

*--service-start*

This will start the Redis service. Upon successful start, a success message will be displayed and Redis will begin running.

For instance:

redis-server --service-start

Stopping the Service
--------------------

*--service-stop*

This will stop the Redis service. Upon successful termination a success message will be displayed and Redis will exit.

For instance:

redis-server --service-stop

Naming the Service
------------------

*--service-name **name***

This optional argument may be used with any of the preceding commands to set the name of the installed service. This argument should follow the service-install, service-start, service-stop or service-uninstall commands, and precede any arguments to be passed to Redis via the service-install command.

The following would install and start three separate instances of Redis as a service:

redis-server --service-install --service-name redisService1 --port 10001

redis-server --service-start --service-name redisService1

redis-server --service-install --service-name redisService2 --port 10002

redis-server --service-start --service-name redisService2

redis-server --service-install --service-name redisService3 --port 10003

redis-server --service-start --service-name redisService3
13 changes: 13 additions & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
version: 2.8.21.{build}

branches:
# whitelist
only:
- '2.8'
- appveyor

install:
- git submodule -q update --init

build:
project: msvs\RedisServer.sln
4 changes: 4 additions & 0 deletions deps/geohash-int/geohash.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
*/
#include "geohash.h"

#ifdef _WIN32
#define inline __inline
#endif

/**
* Hashing works like this:
* Divide the world into 4 buckets. Label each one as such:
Expand Down
6 changes: 6 additions & 0 deletions deps/geohash-int/geohash_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@

#include "geohash_helper.h"

#ifdef _WIN32
#define inline __inline
#define _USE_MATH_DEFINES // for C
#include <math.h>
#endif

#define D_R (M_PI / 180.0)
#define R_MAJOR 6378137.0
#define R_MINOR 6356752.3142
Expand Down
16 changes: 16 additions & 0 deletions deps/hiredis/adapters/ae.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@
#ifndef __HIREDIS_AE_H__
#define __HIREDIS_AE_H__
#include <sys/types.h>
#ifdef _WIN32
#include "..\..\src\ae.h"
#else
#include <ae.h>
#endif
#include "../hiredis.h"
#include "../async.h"

Expand Down Expand Up @@ -65,6 +69,15 @@ static void redisAeAddRead(void *privdata) {
}
}

#ifdef _WIN32
static void redisAeForceAddRead(void *privdata) {
redisAeEvents *e = (redisAeEvents*)privdata;
aeEventLoop *loop = e->loop;
e->reading = 1;
aeCreateFileEvent(loop, e->fd, AE_READABLE, redisAeReadEvent, e);
}
#endif

static void redisAeDelRead(void *privdata) {
redisAeEvents *e = (redisAeEvents*)privdata;
aeEventLoop *loop = e->loop;
Expand Down Expand Up @@ -116,6 +129,9 @@ static int redisAeAttach(aeEventLoop *loop, redisAsyncContext *ac) {

/* Register functions to start/stop listening for events */
ac->ev.addRead = redisAeAddRead;
#ifdef _WIN32
ac->ev.forceAddRead = redisAeForceAddRead;
#endif
ac->ev.delRead = redisAeDelRead;
ac->ev.addWrite = redisAeAddWrite;
ac->ev.delWrite = redisAeDelWrite;
Expand Down
Loading

0 comments on commit 649cd88

Please sign in to comment.