% A distributed pixel cache is an extension of the traditional pixel cache
% available on a single host. The distributed pixel cache may span multiple
% servers so that it can grow in size and transactional capacity to support
-% very large images. Start up the pixel cache server on one or more machines.
+% very large images. Start up the pixel cache server on one or more machines.
% When you read or operate on an image and the local pixel cache resources are
% exhausted, ImageMagick contacts one or more of these remote pixel servers to
% store or retrieve pixels.
Include declarations.
*/
#include "MagickCore/studio.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/cache-private.h"
#include "MagickCore/distribute-cache.h"
#include "MagickCore/distribute-cache-private.h"
#include "MagickCore/exception.h"
#include "MagickCore/exception-private.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/image.h"
#include "MagickCore/locale_.h"
#include "MagickCore/memory_.h"
+#include "MagickCore/policy.h"
+#include "MagickCore/random_.h"
#include "MagickCore/registry.h"
#include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
#if defined(MAGICKCORE_HAVE_SOCKET)
-#include <sys/socket.h>
+#include <netinet/in.h>
#include <netdb.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
#endif
\f
+/*
+ Define declarations.
+*/
+#define DPCHostname "127.0.0.1"
+#define DPCPort 6668
+#define DPCSessionKeyLength 8
+\f
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% o exception: return any errors or warnings in this structure.
%
*/
+
+static MagickSizeType CRC64(const unsigned char *message,const size_t length)
+{
+ MagickSizeType
+ crc;
+
+ register ssize_t
+ i;
+
+ static MagickBooleanType
+ crc_initial = MagickFalse;
+
+ static MagickSizeType
+ crc_xor[256];
+
+ if (crc_initial == MagickFalse)
+ {
+ MagickSizeType
+ alpha;
+
+ for (i=0; i < 256; i++)
+ {
+ register ssize_t
+ j;
+
+ alpha=(MagickSizeType) i;
+ for (j=0; j < 8; j++)
+ {
+ if ((alpha & 0x01) == 0)
+ alpha>>=1;
+ else
+ alpha=(MagickSizeType) ((alpha >> 1) ^
+ MagickULLConstant(0xd800000000000000));
+ }
+ crc_xor[i]=alpha;
+ }
+ crc_initial=MagickTrue;
+ }
+ crc=0;
+ for (i=0; i < (ssize_t) length; i++)
+ crc=crc_xor[(crc ^ message[i]) & 0xff] ^ (crc >> 8);
+ return(crc);
+}
+
+static int ConnectPixelCacheServer(const char *hostname,const int port,
+ MagickSizeType *session_key,ExceptionInfo *exception)
+{
+#if defined(MAGICKCORE_HAVE_SOCKET)
+ char
+ secret[MaxTextExtent];
+
+ const char
+ *shared_secret;
+
+ int
+ client_socket,
+ status;
+
+ ssize_t
+ count;
+
+ struct hostent
+ *host;
+
+ struct sockaddr_in
+ address;
+
+ unsigned char
+ session[MaxTextExtent];
+
+ /*
+ Connect to distributed pixel cache and get session key.
+ */
+ *session_key=0;
+ shared_secret=GetPolicyValue("shared-secret");
+ if (shared_secret == (const char *) NULL)
+ {
+ (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
+ "DistributedPixelCache","'%s'","shared secret expected");
+ return(-1);
+ }
+ (void) CopyMagickString((char *) session,shared_secret,MaxTextExtent-
+ DPCSessionKeyLength);
+ host=gethostbyname(hostname);
+ client_socket=socket(AF_INET,SOCK_STREAM,0);
+ if (client_socket == -1)
+ {
+ (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
+ "DistributedPixelCache","'%s'",hostname);
+ return(-1);
+ }
+ (void) ResetMagickMemory(&address,0,sizeof(address));
+ address.sin_family=AF_INET;
+ address.sin_port=htons((uint16_t) port);
+ address.sin_addr=(*((struct in_addr *) host->h_addr));
+ status=connect(client_socket,(struct sockaddr *) &address,(socklen_t)
+ sizeof(struct sockaddr));
+ if (status == -1)
+ {
+ (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
+ "DistributedPixelCache","'%s'",hostname);
+ return(-1);
+ }
+ count=read(client_socket,secret,MaxTextExtent);
+ if (count != -1)
+ {
+ (void) memcpy(session+strlen(shared_secret),secret,(size_t) count);
+ *session_key=CRC64(session,strlen(shared_secret)+count);
+ }
+ if (*session_key == 0)
+ {
+ close(client_socket);
+ client_socket=(-1);
+ }
+ return(client_socket);
+#else
+ (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
+ "DelegateLibrarySupportNotBuiltIn","distributed pixel cache");
+ return(MagickFalse);
+#endif
+}
+
+static char *GetHostname(int *port,ExceptionInfo *exception)
+{
+ char
+ *host,
+ *hosts,
+ **hostlist;
+
+ int
+ argc;
+
+ register ssize_t
+ i;
+
+ static size_t
+ id = 0;
+
+ /*
+ Parse host list (e.g. 192.168.100.1:6668,192.168.100.2:6668).
+ */
+ hosts=(char *) GetImageRegistry(StringRegistryType,"cache:hosts",
+ exception);
+ if (hosts == (char *) NULL)
+ {
+ *port=DPCPort;
+ return(AcquireString(DPCHostname));
+ }
+ (void) SubstituteString(&hosts,","," ");
+ hostlist=StringToArgv(hosts,&argc);
+ hosts=DestroyString(hosts);
+ if (hostlist == (char **) NULL)
+ {
+ *port=DPCPort;
+ return(AcquireString(DPCHostname));
+ }
+ hosts=AcquireString(hostlist[(id++ % (argc-1))+1]);
+ for (i=0; i < (ssize_t) argc; i++)
+ hostlist[i]=DestroyString(hostlist[i]);
+ hostlist=(char **) RelinquishMagickMemory(hostlist);
+ (void) SubstituteString(&hosts,":"," ");
+ hostlist=StringToArgv(hosts,&argc);
+ if (hostlist == (char **) NULL)
+ {
+ *port=DPCPort;
+ return(AcquireString(DPCHostname));
+ }
+ host=AcquireString(hostlist[1]);
+ if (hostlist[2] == (char *) NULL)
+ *port=DPCPort;
+ else
+ *port=StringToLong(hostlist[2]);
+ for (i=0; i < (ssize_t) argc; i++)
+ hostlist[i]=DestroyString(hostlist[i]);
+ hostlist=(char **) RelinquishMagickMemory(hostlist);
+ return(host);
+}
+
MagickPrivate DistributeCacheInfo *AcquireDistributeCacheInfo(
ExceptionInfo *exception)
{
-#if defined(MAGICKCORE_HAVE_SOCKET) && defined(MAGICKCORE_HAVE_PTHREAD)
+ char
+ *hostname;
+
DistributeCacheInfo
*distribute_cache_info;
- distribute_cache_info=(DistributeCacheInfo *) NULL;
+ MagickSizeType
+ session_key;
+
distribute_cache_info=(DistributeCacheInfo *) AcquireMagickMemory(
sizeof(*distribute_cache_info));
if (distribute_cache_info == (DistributeCacheInfo *) NULL)
(void) ResetMagickMemory(distribute_cache_info,0,
sizeof(*distribute_cache_info));
distribute_cache_info->signature=MagickSignature;
+ /*
+ Contact pixel cache server.
+ */
+ distribute_cache_info->port=0;
+ hostname=GetHostname(&distribute_cache_info->port,exception);
+ session_key=0;
+ distribute_cache_info->file=ConnectPixelCacheServer(hostname,
+ distribute_cache_info->port,&session_key,exception);
+ distribute_cache_info->session_key=session_key;
+ (void) CopyMagickString(distribute_cache_info->hostname,hostname,
+ MaxTextExtent);
+ hostname=DestroyString(hostname);
+ if (distribute_cache_info->file == -1)
+ distribute_cache_info=DestroyDistributeCacheInfo(distribute_cache_info);
return(distribute_cache_info);
-#else
- return((DistributeCacheInfo *) NULL);
-#endif
}
\f
/*
{
assert(distribute_cache_info != (DistributeCacheInfo *) NULL);
assert(distribute_cache_info->signature == MagickSignature);
-#if defined(MAGICKCORE_HAVE_SOCKET)
-#endif
distribute_cache_info->signature=(~MagickSignature);
- distribute_cache_info=(DistributeCacheInfo *)
- RelinquishMagickMemory(distribute_cache_info);
+ distribute_cache_info=(DistributeCacheInfo *) RelinquishMagickMemory(
+ distribute_cache_info);
return(distribute_cache_info);
}
\f
% %
% %
% %
-+ P i x e l C a c h e S e r v e r %
++ D i s t r i b u t e P i x e l C a c h e S e r v e r %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
-% PixelCacheServer() waits on the specified port for commands to create, read,
-% update, or destroy a pixel cache.
+% DistributePixelCacheServer() waits on the specified port for commands to
+% create, read, update, or destroy a pixel cache.
%
-% The format of the PixelCacheServer() method is:
+% The format of the DistributePixelCacheServer() method is:
%
-% void PixelCacheServer(const size_t port)
+% void DistributePixelCacheServer(const size_t port)
%
% A description of each parameter follows:
%
% o exception: return any errors or warnings in this structure.
%
*/
-MagickExport void PixelCacheServer(const size_t port,ExceptionInfo *exception)
+
+static MagickBooleanType CreateDistributeCache(int file,
+ const MagickSizeType session_key)
{
-#if defined(MAGICKCORE_HAVE_SOCKET) && defined(MAGICKCORE_HAVE_PTHREAD)
char
- message[MaxTextExtent],
- service[MaxTextExtent];
+ key[MaxTextExtent];
- int
- file,
+ ExceptionInfo
+ *exception;
+
+ Image
+ *image;
+
+ MagickBooleanType
status;
- register struct addrinfo
+ ssize_t
+ count;
+
+ exception=AcquireExceptionInfo();
+ image=AcquireImage((ImageInfo *) NULL,exception);
+ count=read(file,&image->columns,sizeof(image->columns));
+ if (count != (ssize_t) sizeof(image->columns))
+ return(MagickFalse);
+ count=read(file,&image->rows,sizeof(image->rows));
+ if (count != (ssize_t) sizeof(image->rows))
+ return(MagickFalse);
+ count=read(file,&image->number_channels,sizeof(image->number_channels));
+ if (count != (ssize_t) sizeof(image->number_channels))
+ return(MagickFalse);
+ (void) FormatLocaleString(key,MaxTextExtent,"%.20g",(double) session_key);
+ status=SetImageRegistry(ImageRegistryType,key,image,exception);
+ exception=DestroyExceptionInfo(exception);
+ image=DestroyImage(image);
+ return(status);
+}
+
+static MagickBooleanType DestroyDistributeCache(int file,
+ const MagickSizeType session_key)
+{
+ char
+ key[MaxTextExtent];
+
+ (void) FormatLocaleString(key,MaxTextExtent,"%.20g",(double) session_key);
+ return(DeleteImageRegistry(key));
+}
+
+static MagickBooleanType ReadDistributeCache(int file,
+ const MagickSizeType session_key)
+{
+ char
+ key[MaxTextExtent];
+
+ CacheInfo
+ *cache_info;
+
+ ExceptionInfo
+ *exception;
+
+ Image
+ *image;
+
+ RectangleInfo
+ region;
+
+ register const Quantum
*p;
+ size_t
+ length;
+
ssize_t
count;
- socklen_t
+ exception=AcquireExceptionInfo();
+ (void) FormatLocaleString(key,MaxTextExtent,"%.20g",(double) session_key);
+ image=(Image *) GetImageRegistry(ImageRegistryType,key,exception);
+ exception=DestroyExceptionInfo(exception);
+ if (image == (Image *) NULL)
+ return(MagickFalse);
+ cache_info=(CacheInfo *) image->cache;
+ count=read(file,®ion.width,sizeof(region.width));
+ if (count != (ssize_t) sizeof(region.width))
+ return(MagickFalse);
+ count=read(file,®ion.height,sizeof(region.height));
+ if (count != (ssize_t) sizeof(region.height))
+ return(MagickFalse);
+ count=read(file,®ion.x,sizeof(region.x));
+ if (count != (ssize_t) sizeof(region.width))
+ return(MagickFalse);
+ count=read(file,®ion.y,sizeof(region.y));
+ if (count != (ssize_t) sizeof(region.y))
+ return(MagickFalse);
+ length=(size_t) (region.width*cache_info->number_channels*sizeof(Quantum));
+ exception=AcquireExceptionInfo();
+ p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
+ exception);
+ exception=DestroyExceptionInfo(exception);
+ if (p != (const Quantum *) NULL)
+ return(MagickFalse);
+ count=write(file,p,length);
+ if (count != (ssize_t) length)
+ return(MagickFalse);
+ return(MagickTrue);
+}
+
+static MagickBooleanType WriteDistributeCache(int file,
+ const MagickSizeType session_key)
+{
+ char
+ key[MaxTextExtent];
+
+ CacheInfo
+ *cache_info;
+
+ ExceptionInfo
+ *exception;
+
+ Image
+ *image;
+
+ MagickBooleanType
+ status;
+
+ RectangleInfo
+ region;
+
+ register Quantum
+ *p;
+
+ size_t
length;
- struct addrinfo
- hints,
- *result;
+ ssize_t
+ count;
- struct sockaddr_storage
- address;
+ exception=AcquireExceptionInfo();
+ (void) FormatLocaleString(key,MaxTextExtent,"%.20g",(double) session_key);
+ image=(Image *) GetImageRegistry(ImageRegistryType,key,exception);
+ exception=DestroyExceptionInfo(exception);
+ if (image == (Image *) NULL)
+ return(MagickFalse);
+ cache_info=(CacheInfo *) image->cache;
+ count=read(file,®ion.width,sizeof(region.width));
+ if (count != (ssize_t) sizeof(region.width))
+ return(MagickFalse);
+ count=read(file,®ion.height,sizeof(region.height));
+ if (count != (ssize_t) sizeof(region.height))
+ return(MagickFalse);
+ count=read(file,®ion.x,sizeof(region.x));
+ if (count != (ssize_t) sizeof(region.width))
+ return(MagickFalse);
+ count=read(file,®ion.y,sizeof(region.y));
+ if (count != (ssize_t) sizeof(region.y))
+ return(MagickFalse);
+ length=(size_t) (region.width*cache_info->number_channels*sizeof(Quantum));
+ p=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
+ exception);
+ exception=DestroyExceptionInfo(exception);
+ if (p != (Quantum *) NULL)
+ return(MagickFalse);
+ count=read(file,p,length);
+ if (count != (ssize_t) length)
+ return(MagickFalse);
+ status=SyncAuthenticPixels(image,exception);
+ return(status);
+}
- (void) ResetMagickMemory(&hints,0,sizeof(hints));
- hints.ai_family=AF_UNSPEC; /* allow IPv4 or IPv6 */
- hints.ai_socktype=SOCK_DGRAM; /* datagram socket */
- hints.ai_flags=AI_PASSIVE; /* for wildcard IP address */
- hints.ai_protocol=0; /* any protocol */
- (void) FormatLocaleString(service,MaxTextExtent,"%.20g",(double) port);
- status=getaddrinfo((const char *) NULL,service,&hints,&result);
- if (status != 0)
- {
- (void) fprintf(stderr,"getaddrinfo: %s\n", gai_strerror(status));
- exit(EXIT_FAILURE);
- }
- for (p=result; p != (struct addrinfo *) NULL; p=p->ai_next)
+static void *DistributePixelCacheClient(void *socket)
+{
+ const char
+ *shared_secret;
+
+ int
+ client_socket,
+ status;
+
+ MagickSizeType
+ key,
+ session_key;
+
+ RandomInfo
+ *random_info;
+
+ ssize_t
+ count;
+
+ StringInfo
+ *secret;
+
+ unsigned char
+ command,
+ session[MaxTextExtent];
+
+ /*
+ Generate session key.
+ */
+ shared_secret=GetPolicyValue("shared-secret");
+ if (shared_secret == (const char *) NULL)
+ ThrowFatalException(CacheFatalError,"shared secret expected");
+ (void) CopyMagickString((char *) session,shared_secret,MaxTextExtent-
+ DPCSessionKeyLength);
+ random_info=AcquireRandomInfo();
+ secret=GetRandomKey(random_info,DPCSessionKeyLength);
+ (void) memcpy(session+strlen(shared_secret),GetStringInfoDatum(secret),
+ DPCSessionKeyLength);
+ session_key=CRC64(session,strlen(shared_secret)+DPCSessionKeyLength);
+ random_info=DestroyRandomInfo(random_info);
+ client_socket=(*(int *) socket);
+ count=write(client_socket,GetStringInfoDatum(secret),DPCSessionKeyLength);
+ secret=DestroyStringInfo(secret);
+ for ( ; ; )
{
- file=socket(p->ai_family, p->ai_socktype,p->ai_protocol);
- if (file == -1)
- continue;
- if (bind(file,p->ai_addr,p->ai_addrlen) == 0)
+ count=read(client_socket,&command,1);
+ if (count <= 0)
break;
- (void) close(file);
- }
- if (p == NULL)
+ count=read(client_socket,&key,sizeof(key));
+ if ((count != (ssize_t) sizeof(key)) && (key != session_key))
+ break;
+ status=MagickFalse;
+ switch (command)
{
- (void) fprintf(stderr,"Could not bind\n");
- exit(EXIT_FAILURE);
+ case 'c':
+ {
+ status=CreateDistributeCache(client_socket,session_key);
+ break;
+ }
+ case 'd':
+ {
+ status=DestroyDistributeCache(client_socket,session_key);
+ break;
+ }
+ case 'r':
+ {
+ status=ReadDistributeCache(client_socket,session_key);
+ break;
+ }
+ case 'w':
+ {
+ status=WriteDistributeCache(client_socket,session_key);
+ break;
+ }
+ default:
+ break;
}
- freeaddrinfo(result);
+ count=write(client_socket,&status,sizeof(status));
+ if (count != (ssize_t) sizeof(status))
+ break;
+ }
+ return((void *) NULL);
+}
+
+MagickExport void DistributePixelCacheServer(const size_t port,
+ ExceptionInfo *exception)
+{
+#if defined(MAGICKCORE_HAVE_SOCKET) && defined(MAGICKCORE_THREAD_SUPPORT)
+ int
+ server_socket,
+ status;
+
+ pthread_attr_t
+ attributes;
+
+ pthread_t
+ threads;
+
+ struct sockaddr_in
+ address;
+
+ /*
+ Launch distributed pixel cache server.
+ */
+ server_socket=socket(AF_INET,SOCK_STREAM,0);
+ address.sin_family=AF_INET;
+ address.sin_port=htons(port);
+ address.sin_addr.s_addr=htonl(INADDR_ANY);
+ status=bind(server_socket,(struct sockaddr *) &address,(socklen_t)
+ sizeof(address));
+ if (status != 0)
+ ThrowFatalException(CacheFatalError,"UnableToBind");
+ status=listen(server_socket,32);
+ if (status != 0)
+ ThrowFatalException(CacheFatalError,"UnableToListen");
+ pthread_attr_init(&attributes);
for ( ; ; )
{
- char
- host[NI_MAXHOST],
- service[NI_MAXSERV];
-
- ssize_t
- bytes;
-
- length=(socklen_t) sizeof(struct sockaddr_storage);
- count=recvfrom(file,message,MaxTextExtent,0,(struct sockaddr *) &address,
- &length);
- if (count == -1)
- continue;
- status=getnameinfo((struct sockaddr *) &address,length,host,NI_MAXHOST,
- service,NI_MAXSERV,NI_NUMERICSERV);
- if (status == 0)
- (void) printf("received %ld bytes from %s:%s\n",(long) count,host,
- service);
- else
- (void) fprintf(stderr,"getnameinfo: %s\n", gai_strerror(status));
- bytes=sendto(file,message,(size_t) count,0,(struct sockaddr *) &address,
- length);
- if (bytes != count)
- (void) fprintf(stderr,"error sending response\n");
+ int
+ client_socket;
+
+ socklen_t
+ length;
+
+ length=(socklen_t) sizeof(address);
+ client_socket=accept(server_socket,(struct sockaddr *) &address,&length);
+ if (client_socket == -1)
+ ThrowFatalException(CacheFatalError,"UnableToEstablishConnection");
+ status=pthread_create(&threads,&attributes,DistributePixelCacheClient,
+ (void *) &client_socket);
+ if (status == -1)
+ ThrowFatalException(CacheFatalError,"UnableToCreateClientThread");
}
+ (void) close(server_socket);
#else
- (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
- "DelegateLibrarySupportNotBuiltIn","'%s' (socket)",
- "distributed pixel cache");
+ ThrowFatalException(MissingDelegateError,"distributed pixel cache");
#endif
}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% %
+% %
+% %
+% O p e n D i s t r i b u t e P i x e l C a c h e %
+% %
+% %
+% %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% OpenDistributePixelCache() opens a pixel cache on a remote server.
+%
+% The format of the OpenDistributePixelCache method is:
+%
+% MagickBooleanType *OpenDistributePixelCache(
+% DistributeCacheInfo *distribute_cache_info,Image *image)
+%
+% A description of each parameter follows:
+%
+% o distribute_cache_info: the distributed cache info.
+%
+% o image: the image.
+%
+*/
+MagickPrivate MagickBooleanType OpenDistributePixelCache(
+ DistributeCacheInfo *distribute_cache_info,Image *image)
+{
+ int
+ file;
+
+ MagickBooleanType
+ status;
+
+ MagickSizeType
+ session_key;
+
+ ssize_t
+ count;
+
+ assert(distribute_cache_info != (DistributeCacheInfo *) NULL);
+ assert(distribute_cache_info->signature == MagickSignature);
+ assert(image != (Image *) NULL);
+ assert(image->signature == MagickSignature);
+ file=distribute_cache_info->file;
+ session_key=distribute_cache_info->session_key;
+ count=write(file,"c",1);
+ if (count != 1)
+ return(MagickFalse);
+ count=write(file,&session_key,sizeof(session_key));
+ if (count != (ssize_t) sizeof(session_key))
+ return(MagickFalse);
+ count=write(file,&image->columns,sizeof(image->columns));
+ if (count != (ssize_t) sizeof(image->columns))
+ return(MagickFalse);
+ count=write(file,&image->rows,sizeof(image->rows));
+ if (count != (ssize_t) sizeof(image->rows))
+ return(MagickFalse);
+ count=write(file,&image->number_channels,sizeof(image->number_channels));
+ if (count != (ssize_t) sizeof(image->number_channels))
+ return(MagickFalse);
+ count=read(file,&status,sizeof(status));
+ if (count != (ssize_t) sizeof(status))
+ return(MagickFalse);
+ return(MagickTrue);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% %
+% %
+% %
+% R e a d D i s t r i b u t e P i x e l C a c h e %
+% %
+% %
+% %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% ReadDistributePixelCache() reads pixels from the specified region of the
+% distributed pixel cache.
+%
+% The format of the ReadDistributePixelCache method is:
+%
+% MagickBooleanType *ReadDistributePixelCache(
+% DistributeCacheInfo *distribute_cache_info,const RectangleInfo *region,
+% Quantum *pixels)
+%
+% A description of each parameter follows:
+%
+% o distribute_cache_info: the distributed cache info.
+%
+% o image: the image.
+%
+% o region: read the pixels from this region of the image.
+%
+% o pixels: read these pixels from the pixel cache.
+%
+*/
+MagickPrivate MagickBooleanType ReadDistributePixelCache(
+ DistributeCacheInfo *distribute_cache_info,const RectangleInfo *region,
+ Quantum *pixels)
+{
+ CacheInfo
+ *cache_info;
+
+ char
+ key[MaxTextExtent];
+
+ ExceptionInfo
+ *exception;
+
+ int
+ file;
+
+ Image
+ *image;
+
+ MagickBooleanType
+ status;
+
+ MagickSizeType
+ session_key;
+
+ size_t
+ length;
+
+ ssize_t
+ count;
+
+ assert(distribute_cache_info != (DistributeCacheInfo *) NULL);
+ assert(distribute_cache_info->signature == MagickSignature);
+ assert(region != (RectangleInfo *) NULL);
+ assert(pixels != (Quantum *) NULL);
+ exception=AcquireExceptionInfo();
+ (void) FormatLocaleString(key,MaxTextExtent,"%.20g",(double) session_key);
+ image=(Image *) GetImageRegistry(ImageRegistryType,key,exception);
+ exception=DestroyExceptionInfo(exception);
+ if (image == (Image *) NULL)
+ return(MagickFalse);
+ cache_info=(CacheInfo *) image->cache;
+ file=distribute_cache_info->file;
+ session_key=distribute_cache_info->session_key;
+ count=write(file,"r",1);
+ if (count != 1)
+ return(MagickFalse);
+ count=write(file,&session_key,sizeof(session_key));
+ if (count != (ssize_t) sizeof(session_key))
+ return(MagickFalse);
+ count=write(file,®ion->width,sizeof(region->width));
+ if (count != (ssize_t) sizeof(region->width))
+ return(MagickFalse);
+ count=write(file,®ion->height,sizeof(region->height));
+ if (count != (ssize_t) sizeof(region->height))
+ return(MagickFalse);
+ count=write(file,®ion->x,sizeof(region->x));
+ if (count != (ssize_t) sizeof(region->x))
+ return(MagickFalse);
+ count=write(file,®ion->y,sizeof(region->x));
+ if (count != (ssize_t) sizeof(region->y))
+ return(MagickFalse);
+ length=(size_t) (region->width*cache_info->number_channels*sizeof(Quantum));
+ count=read(file,(unsigned char *) pixels,length);
+ if (count != (ssize_t) length)
+ return(MagickFalse);
+ count=read(file,&status,sizeof(status));
+ if (count != (ssize_t) sizeof(status))
+ return(MagickFalse);
+ return(MagickTrue);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% %
+% %
+% %
+% R e l i n q u i s h D i s t r i b u t e P i x e l C a c h e %
+% %
+% %
+% %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% RelinquishDistributePixelCache() frees resources acquired with
+% OpenDistributePixelCache().
+%
+% The format of the RelinquishDistributePixelCache method is:
+%
+% void RelinquishDistributePixelCache(
+% DistributeCacheInfo *distribute_cache_info)
+%
+% A description of each parameter follows:
+%
+% o distribute_cache_info: the distributed cache info.
+%
+*/
+MagickPrivate void RelinquishDistributePixelCache(
+ DistributeCacheInfo *distribute_cache_info)
+{
+ int
+ file;
+
+ MagickSizeType
+ session_key;
+
+ assert(distribute_cache_info != (DistributeCacheInfo *) NULL);
+ assert(distribute_cache_info->signature == MagickSignature);
+ file=distribute_cache_info->file;
+ session_key=distribute_cache_info->session_key;
+ (void) write(file,"c",1);
+ (void) write(file,&session_key,sizeof(session_key));
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% %
+% %
+% %
+% W r i t e D i s t r i b u t e P i x e l C a c h e %
+% %
+% %
+% %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% WriteDistributePixelCache() writes image pixels to the specified region of
+% the distributed pixel cache.
+
+%
+% The format of the WriteDistributePixelCache method is:
+%
+% MagickBooleanType *WriteDistributePixelCache(
+% DistributeCacheInfo *distribute_cache_info,const RectangleInfo *region,
+% const Quantum *pixels)
+%
+% A description of each parameter follows:
+%
+% o distribute_cache_info: the distributed cache info.
+%
+% o image: the image.
+%
+% o region: write the pixels to this region of the image.
+%
+% o pixels: write these pixels to the pixel cache.
+%
+*/
+MagickPrivate MagickBooleanType WriteDistributePixelCache(
+ DistributeCacheInfo *distribute_cache_info,const RectangleInfo *region,
+ const Quantum *pixels)
+{
+ CacheInfo
+ *cache_info;
+
+ char
+ key[MaxTextExtent];
+
+ ExceptionInfo
+ *exception;
+
+ int
+ file;
+
+ Image
+ *image;
+
+ MagickBooleanType
+ status;
+
+ MagickSizeType
+ session_key;
+
+ size_t
+ length;
+
+ ssize_t
+ count;
+
+ assert(distribute_cache_info != (DistributeCacheInfo *) NULL);
+ assert(distribute_cache_info->signature == MagickSignature);
+ assert(region != (RectangleInfo *) NULL);
+ assert(pixels != (Quantum *) NULL);
+ exception=AcquireExceptionInfo();
+ (void) FormatLocaleString(key,MaxTextExtent,"%.20g",(double) session_key);
+ image=(Image *) GetImageRegistry(ImageRegistryType,key,exception);
+ exception=DestroyExceptionInfo(exception);
+ if (image == (Image *) NULL)
+ return(MagickFalse);
+ cache_info=(CacheInfo *) image->cache;
+ file=distribute_cache_info->file;
+ session_key=distribute_cache_info->session_key;
+ count=write(file,"u",1);
+ if (count != 1)
+ return(MagickFalse);
+ count=write(file,&session_key,sizeof(session_key));
+ if (count != (ssize_t) sizeof(session_key))
+ return(MagickFalse);
+ count=write(file,®ion->width,sizeof(region->width));
+ if (count != (ssize_t) sizeof(region->width))
+ return(MagickFalse);
+ count=write(file,®ion->height,sizeof(region->height));
+ if (count != (ssize_t) sizeof(region->height))
+ return(MagickFalse);
+ count=write(file,®ion->x,sizeof(region->x));
+ if (count != (ssize_t) sizeof(region->x))
+ return(MagickFalse);
+ count=write(file,®ion->y,sizeof(region->x));
+ if (count != (ssize_t) sizeof(region->y))
+ return(MagickFalse);
+ length=(size_t) (region->width*cache_info->number_channels*sizeof(Quantum));
+ count=write(file,(unsigned char *) pixels,length);
+ if (count != (ssize_t) length)
+ return(MagickFalse);
+ count=read(file,&status,sizeof(status));
+ if (count != (ssize_t) sizeof(status))
+ return(MagickFalse);
+ return(MagickTrue);
+}