2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5 % DDDD IIIII SSSSS TTTTT RRRR IIIII BBBB U U TTTTT EEEEE %
6 % D D I SS T R R I B B U U T E %
7 % D D I SSS T RRRR I BBBB U U T EEE %
8 % D D I SS T R R I B B U U T E %
9 % DDDDA IIIII SSSSS T R R IIIII BBBB UUU T EEEEE %
11 % CCCC AAA CCCC H H EEEEE %
13 % C AAAAA C HHHHH EEE %
15 % CCCC A A CCCC H H EEEEE %
18 % MagickCore Distributed Pixel Cache Methods %
25 % Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization %
26 % dedicated to making software imaging solutions freely available. %
28 % You may not use this file except in compliance with the License. You may %
29 % obtain a copy of the License at %
31 % http://www.imagemagick.org/script/license.php %
33 % Unless required by applicable law or agreed to in writing, software %
34 % distributed under the License is distributed on an "AS IS" BASIS, %
35 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
36 % See the License for the specific language governing permissions and %
37 % limitations under the License. %
39 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
41 % A distributed pixel cache is an extension of the traditional pixel cache
42 % available on a single host. The distributed pixel cache may span multiple
43 % servers so that it can grow in size and transactional capacity to support
44 % very large images. Start up the pixel cache server on one or more machines.
45 % When you read or operate on an image and the local pixel cache resources are
46 % exhausted, ImageMagick contacts one or more of these remote pixel servers to
47 % store or retrieve pixels.
54 #include "MagickCore/studio.h"
55 #include "MagickCore/cache.h"
56 #include "MagickCore/cache-private.h"
57 #include "MagickCore/distribute-cache.h"
58 #include "MagickCore/distribute-cache-private.h"
59 #include "MagickCore/exception.h"
60 #include "MagickCore/exception-private.h"
61 #include "MagickCore/geometry.h"
62 #include "MagickCore/image.h"
63 #include "MagickCore/list.h"
64 #include "MagickCore/locale_.h"
65 #include "MagickCore/memory_.h"
66 #include "MagickCore/pixel.h"
67 #include "MagickCore/policy.h"
68 #include "MagickCore/random_.h"
69 #include "MagickCore/registry.h"
70 #include "MagickCore/splay-tree.h"
71 #include "MagickCore/string_.h"
72 #include "MagickCore/string-private.h"
73 #include "MagickCore/version.h"
74 #if defined(MAGICKCORE_HAVE_SOCKET)
75 #include <netinet/in.h>
77 #include <sys/socket.h>
78 #include <arpa/inet.h>
84 #define DPCHostname "127.0.0.1"
85 #define DPCPendingConnections 10
87 #define DPCSessionKeyLength 8
90 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
94 + A c q u i r e D i s t r i b u t e C a c h e I n f o %
98 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
100 % AcquireDistributeCacheInfo() allocates the DistributeCacheInfo structure.
102 % The format of the AcquireDistributeCacheInfo method is:
104 % DistributeCacheInfo *AcquireDistributeCacheInfo(ExceptionInfo *exception)
106 % A description of each parameter follows:
108 % o exception: return any errors or warnings in this structure.
112 static MagickSizeType CRC64(const unsigned char *message,
113 const MagickSizeType length)
118 register MagickOffsetType
121 static MagickBooleanType
122 crc_initial = MagickFalse;
124 static MagickSizeType
128 Generate a 64-bit cyclic redundancy check for the message.
130 if (crc_initial == MagickFalse)
135 for (i=0; i < 256; i++)
137 register MagickOffsetType
140 alpha=(MagickSizeType) i;
141 for (j=0; j < 8; j++)
143 if ((alpha & 0x01) == 0)
146 alpha=(MagickSizeType) ((alpha >> 1) ^
147 MagickULLConstant(0xd800000000000000));
151 crc_initial=MagickTrue;
154 for (i=0; i < (MagickOffsetType) length; i++)
155 crc=crc_xor[(crc ^ message[i]) & 0xff] ^ (crc >> 8);
159 static inline MagickSizeType MagickMin(const MagickSizeType x,
160 const MagickSizeType y)
167 static inline MagickOffsetType dpc_read(int file,const MagickSizeType length,
168 unsigned char *restrict message)
170 register MagickOffsetType
177 for (i=0; i < (MagickOffsetType) length; i+=count)
179 count=recv(file,message+i,(size_t) MagickMin(length-i,(MagickSizeType)
191 static int ConnectPixelCacheServer(const char *hostname,const int port,
192 MagickSizeType *session_key,ExceptionInfo *exception)
194 #if defined(MAGICKCORE_HAVE_SOCKET)
196 service[MaxTextExtent];
208 register unsigned char
216 secret[MaxTextExtent],
217 session[2*MaxTextExtent];
220 Connect to distributed pixel cache and get session key.
223 shared_secret=GetPolicyValue("shared-secret");
224 if (shared_secret == (const char *) NULL)
226 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
227 "DistributedPixelCache","'%s'","shared secret expected");
231 (void) CopyMagickString((char *) p,shared_secret,MaxTextExtent);
232 p+=strlen(shared_secret);
233 (void) ResetMagickMemory(&hint,0,sizeof(hint));
234 hint.ai_family=AF_INET;
235 hint.ai_socktype=SOCK_STREAM;
236 hint.ai_flags=AI_PASSIVE;
237 (void) FormatLocaleString(service,MaxTextExtent,"%d",port);
238 status=getaddrinfo(hostname,service,&hint,&result);
241 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
242 "DistributedPixelCache","'%s'",hostname);
245 client_socket=socket(result->ai_family,result->ai_socktype,
246 result->ai_protocol);
247 if (client_socket == -1)
249 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
250 "DistributedPixelCache","'%s'",hostname);
253 status=connect(client_socket,result->ai_addr,result->ai_addrlen);
256 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
257 "DistributedPixelCache","'%s'",hostname);
260 count=recv(client_socket,secret,MaxTextExtent,0);
266 (void) memcpy(p,secret,(size_t) count);
268 signature=MagickLibVersion;
269 (void) memcpy(p,&signature,sizeof(signature));
270 p+=sizeof(signature);
271 signature=MAGICKCORE_QUANTUM_DEPTH;
272 (void) memcpy(p,&signature,sizeof(signature));
273 p+=sizeof(signature);
274 signature=MAGICKCORE_HDRI_ENABLE;
275 (void) memcpy(p,&signature,sizeof(signature));
276 p+=sizeof(signature);
277 *session_key=CRC64(session,p-session);
279 if (*session_key == 0)
281 close(client_socket);
284 return(client_socket);
286 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
287 "DelegateLibrarySupportNotBuiltIn","distributed pixel cache");
292 static char *GetHostname(int *port,ExceptionInfo *exception)
309 Parse host list (e.g. 192.168.100.1:6668,192.168.100.2:6668).
311 hosts=(char *) GetImageRegistry(StringRegistryType,"cache:hosts",
313 if (hosts == (char *) NULL)
316 return(AcquireString(DPCHostname));
318 (void) SubstituteString(&hosts,","," ");
319 hostlist=StringToArgv(hosts,&argc);
320 hosts=DestroyString(hosts);
321 if (hostlist == (char **) NULL)
324 return(AcquireString(DPCHostname));
326 hosts=AcquireString(hostlist[(id++ % (argc-1))+1]);
327 for (i=0; i < (ssize_t) argc; i++)
328 hostlist[i]=DestroyString(hostlist[i]);
329 hostlist=(char **) RelinquishMagickMemory(hostlist);
330 (void) SubstituteString(&hosts,":"," ");
331 hostlist=StringToArgv(hosts,&argc);
332 if (hostlist == (char **) NULL)
335 return(AcquireString(DPCHostname));
337 host=AcquireString(hostlist[1]);
338 if (hostlist[2] == (char *) NULL)
341 *port=StringToLong(hostlist[2]);
342 for (i=0; i < (ssize_t) argc; i++)
343 hostlist[i]=DestroyString(hostlist[i]);
344 hostlist=(char **) RelinquishMagickMemory(hostlist);
348 MagickPrivate DistributeCacheInfo *AcquireDistributeCacheInfo(
349 ExceptionInfo *exception)
361 Connect to the distributed pixel cache server.
363 server_info=(DistributeCacheInfo *) AcquireMagickMemory(sizeof(*server_info));
364 if (server_info == (DistributeCacheInfo *) NULL)
365 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
366 (void) ResetMagickMemory(server_info,0,sizeof(*server_info));
367 server_info->signature=MagickSignature;
369 hostname=GetHostname(&server_info->port,exception);
371 server_info->file=ConnectPixelCacheServer(hostname,server_info->port,
372 &session_key,exception);
373 server_info->session_key=session_key;
374 (void) CopyMagickString(server_info->hostname,hostname,MaxTextExtent);
375 hostname=DestroyString(hostname);
376 if (server_info->file == -1)
377 server_info=DestroyDistributeCacheInfo(server_info);
382 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
386 + D e s t r o y D i s t r i b u t e C a c h e I n f o %
390 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
392 % DestroyDistributeCacheInfo() deallocates memory associated with an
393 % DistributeCacheInfo structure.
395 % The format of the DestroyDistributeCacheInfo method is:
397 % DistributeCacheInfo *DestroyDistributeCacheInfo(
398 % DistributeCacheInfo *server_info)
400 % A description of each parameter follows:
402 % o server_info: the distributed cache info.
405 MagickPrivate DistributeCacheInfo *DestroyDistributeCacheInfo(
406 DistributeCacheInfo *server_info)
408 assert(server_info != (DistributeCacheInfo *) NULL);
409 assert(server_info->signature == MagickSignature);
410 if (server_info->file > 0)
411 (void) close(server_info->file);
412 server_info->signature=(~MagickSignature);
413 server_info=(DistributeCacheInfo *) RelinquishMagickMemory(server_info);
418 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
422 + 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 %
426 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
428 % DistributePixelCacheServer() waits on the specified port for commands to
429 % create, read, update, or destroy a pixel cache.
431 % The format of the DistributePixelCacheServer() method is:
433 % void DistributePixelCacheServer(const int port)
435 % A description of each parameter follows:
437 % o port: connect the distributed pixel cache at this port.
439 % o exception: return any errors or warnings in this structure.
443 static MagickBooleanType DestroyDistributeCache(SplayTreeInfo *registry,
444 int file,const MagickSizeType session_key)
447 Destroy distributed pixel cache.
449 return(DeleteNodeFromSplayTree(registry,(const void *) session_key));
452 static inline MagickOffsetType dpc_send(int file,const MagickSizeType length,
453 const unsigned char *restrict message)
458 register MagickOffsetType
462 Ensure a complete message is sent.
465 for (i=0; i < (MagickOffsetType) length; i+=count)
467 count=(MagickOffsetType) send(file,message+i,(size_t) MagickMin(length-i,
468 (MagickSizeType) SSIZE_MAX),MSG_NOSIGNAL);
479 static MagickBooleanType OpenDistributeCache(SplayTreeInfo *registry,
480 int file,const MagickSizeType session_key,ExceptionInfo *exception)
494 register unsigned char
498 message[MaxTextExtent];
501 Open distributed pixel cache.
503 image=AcquireImage((ImageInfo *) NULL,exception);
504 if (image == (Image *) NULL)
506 length=sizeof(image->storage_class)+sizeof(image->colorspace)+
507 sizeof(image->alpha_trait)+sizeof(image->mask)+sizeof(image->columns)+
508 sizeof(image->rows)+sizeof(image->number_channels)+MaxPixelChannels*
509 sizeof(*image->channel_map)+sizeof(image->metacontent_extent);
510 count=dpc_read(file,length,message);
511 if (count != (MagickOffsetType) length)
514 Deserialize image attributes.
517 (void) memcpy(&image->storage_class,p,sizeof(image->storage_class));
518 p+=sizeof(image->storage_class);
519 (void) memcpy(&image->colorspace,p,sizeof(image->colorspace));
520 p+=sizeof(image->colorspace);
521 (void) memcpy(&image->alpha_trait,p,sizeof(image->alpha_trait));
522 p+=sizeof(image->alpha_trait);
523 (void) memcpy(&image->mask,p,sizeof(image->mask));
524 p+=sizeof(image->mask);
525 (void) memcpy(&image->columns,p,sizeof(image->columns));
526 p+=sizeof(image->columns);
527 (void) memcpy(&image->rows,p,sizeof(image->rows));
528 p+=sizeof(image->rows);
529 (void) memcpy(&image->number_channels,p,sizeof(image->number_channels));
530 p+=sizeof(image->number_channels);
531 (void) memcpy(image->channel_map,p,MaxPixelChannels*
532 sizeof(*image->channel_map));
533 p+=MaxPixelChannels*sizeof(*image->channel_map);
534 (void) memcpy(&image->metacontent_extent,p,sizeof(image->metacontent_extent));
535 p+=sizeof(image->metacontent_extent);
536 status=AddValueToSplayTree(registry,(const void *) session_key,image);
540 static MagickBooleanType ReadDistributeCacheMetacontent(SplayTreeInfo *registry,
541 int file,const MagickSizeType session_key,ExceptionInfo *exception)
558 register const Quantum
561 register unsigned char
565 message[MaxTextExtent];
568 Read distributed pixel cache metacontent.
570 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
571 if (image == (Image *) NULL)
573 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
574 sizeof(region.y)+sizeof(length);
575 count=dpc_read(file,length,message);
576 if (count != (MagickOffsetType) length)
579 (void) memcpy(®ion.width,q,sizeof(region.width));
580 q+=sizeof(region.width);
581 (void) memcpy(®ion.height,q,sizeof(region.height));
582 q+=sizeof(region.height);
583 (void) memcpy(®ion.x,q,sizeof(region.x));
585 (void) memcpy(®ion.y,q,sizeof(region.y));
587 (void) memcpy(&length,q,sizeof(length));
589 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
591 if (p == (const Quantum *) NULL)
593 metacontent=GetVirtualMetacontent(image);
594 count=dpc_send(file,length,metacontent);
595 if (count != (MagickOffsetType) length)
600 static MagickBooleanType ReadDistributeCachePixels(SplayTreeInfo *registry,
601 int file,const MagickSizeType session_key,ExceptionInfo *exception)
615 register const Quantum
618 register unsigned char
622 message[MaxTextExtent];
625 Read distributed pixel cache pixels.
627 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
628 if (image == (Image *) NULL)
630 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
631 sizeof(region.y)+sizeof(length);
632 count=dpc_read(file,length,message);
633 if (count != (MagickOffsetType) length)
636 (void) memcpy(®ion.width,q,sizeof(region.width));
637 q+=sizeof(region.width);
638 (void) memcpy(®ion.height,q,sizeof(region.height));
639 q+=sizeof(region.height);
640 (void) memcpy(®ion.x,q,sizeof(region.x));
642 (void) memcpy(®ion.y,q,sizeof(region.y));
644 (void) memcpy(&length,q,sizeof(length));
646 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
648 if (p == (const Quantum *) NULL)
650 count=dpc_send(file,length,(unsigned char *) p);
651 if (count != (MagickOffsetType) length)
656 static void *RelinquishImageRegistry(void *image)
658 return((void *) DestroyImageList((Image *) image));
661 static MagickBooleanType WriteDistributeCacheMetacontent(
662 SplayTreeInfo *registry,int file,const MagickSizeType session_key,
663 ExceptionInfo *exception)
683 register unsigned char
687 message[MaxTextExtent],
691 Write distributed pixel cache metacontent.
693 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
694 if (image == (Image *) NULL)
696 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
697 sizeof(region.y)+sizeof(length);
698 count=dpc_read(file,length,message);
699 if (count != (MagickOffsetType) length)
702 (void) memcpy(®ion.width,p,sizeof(region.width));
703 p+=sizeof(region.width);
704 (void) memcpy(®ion.height,p,sizeof(region.height));
705 p+=sizeof(region.height);
706 (void) memcpy(®ion.x,p,sizeof(region.x));
708 (void) memcpy(®ion.y,p,sizeof(region.y));
710 (void) memcpy(&length,p,sizeof(length));
712 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
714 if (q == (Quantum *) NULL)
716 metacontent=GetAuthenticMetacontent(image);
717 count=dpc_read(file,length,metacontent);
718 if (count != (MagickOffsetType) length)
720 status=SyncAuthenticPixels(image,exception);
724 static MagickBooleanType WriteDistributeCachePixels(SplayTreeInfo *registry,
725 int file,const MagickSizeType session_key,ExceptionInfo *exception)
745 register unsigned char
749 message[MaxTextExtent];
752 Write distributed pixel cache pixels.
754 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
755 if (image == (Image *) NULL)
757 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
758 sizeof(region.y)+sizeof(length);
759 count=dpc_read(file,length,message);
760 if (count != (MagickOffsetType) length)
763 (void) memcpy(®ion.width,p,sizeof(region.width));
764 p+=sizeof(region.width);
765 (void) memcpy(®ion.height,p,sizeof(region.height));
766 p+=sizeof(region.height);
767 (void) memcpy(®ion.x,p,sizeof(region.x));
769 (void) memcpy(®ion.y,p,sizeof(region.y));
771 (void) memcpy(&length,p,sizeof(length));
773 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
775 if (q == (Quantum *) NULL)
777 count=dpc_read(file,length,(unsigned char *) q);
778 if (count != (MagickOffsetType) length)
780 status=SyncAuthenticPixels(image,exception);
784 static void *DistributePixelCacheClient(void *socket)
806 register unsigned char
820 session[2*MaxTextExtent];
823 Distributed pixel cache client.
825 shared_secret=GetPolicyValue("shared-secret");
826 if (shared_secret == (const char *) NULL)
827 ThrowFatalException(CacheFatalError,"shared secret expected");
829 (void) CopyMagickString((char *) p,shared_secret,MaxTextExtent);
830 p+=strlen(shared_secret);
831 random_info=AcquireRandomInfo();
832 secret=GetRandomKey(random_info,DPCSessionKeyLength);
833 (void) memcpy(p,GetStringInfoDatum(secret),DPCSessionKeyLength);
834 p+=DPCSessionKeyLength;
835 signature=MagickLibVersion;
836 (void) memcpy(p,&signature,sizeof(signature));
837 p+=sizeof(signature);
838 signature=MAGICKCORE_QUANTUM_DEPTH;
839 (void) memcpy(p,&signature,sizeof(signature));
840 p+=sizeof(signature);
841 signature=MAGICKCORE_HDRI_ENABLE;
842 (void) memcpy(p,&signature,sizeof(signature));
843 p+=sizeof(signature);
844 session_key=CRC64(session,p-session);
845 random_info=DestroyRandomInfo(random_info);
846 exception=AcquireExceptionInfo();
847 registry=NewSplayTree((int (*)(const void *,const void *)) NULL,
848 (void *(*)(void *)) NULL,RelinquishImageRegistry);
849 client_socket=(*(int *) socket);
850 count=dpc_send(client_socket,DPCSessionKeyLength,GetStringInfoDatum(secret));
851 secret=DestroyStringInfo(secret);
854 count=dpc_read(client_socket,1,(unsigned char *) &command);
857 count=dpc_read(client_socket,sizeof(key),(unsigned char *) &key);
858 if ((count != (MagickOffsetType) sizeof(key)) || (key != session_key))
865 status=OpenDistributeCache(registry,client_socket,session_key,
867 count=dpc_send(client_socket,sizeof(status),(unsigned char *) &status);
872 status=ReadDistributeCachePixels(registry,client_socket,session_key,
878 status=ReadDistributeCacheMetacontent(registry,client_socket,
879 session_key,exception);
884 status=WriteDistributeCachePixels(registry,client_socket,session_key,
890 status=WriteDistributeCacheMetacontent(registry,client_socket,
891 session_key,exception);
896 status=DestroyDistributeCache(registry,client_socket,session_key);
902 if (status == MagickFalse)
907 count=dpc_send(client_socket,sizeof(status),(unsigned char *) &status);
908 (void) close(client_socket);
909 exception=DestroyExceptionInfo(exception);
910 registry=DestroySplayTree(registry);
911 return((void *) NULL);
914 MagickExport void DistributePixelCacheServer(const int port,
915 ExceptionInfo *exception)
917 #if defined(MAGICKCORE_HAVE_SOCKET) && defined(MAGICKCORE_THREAD_SUPPORT)
919 service[MaxTextExtent];
931 register struct addrinfo
942 Launch distributed pixel cache server.
944 (void) ResetMagickMemory(&hint,0,sizeof(hint));
945 hint.ai_family=AF_INET;
946 hint.ai_socktype=SOCK_STREAM;
947 hint.ai_flags=AI_PASSIVE;
948 (void) FormatLocaleString(service,MaxTextExtent,"%d",port);
949 status=getaddrinfo((const char *) NULL,service,&hint,&result);
951 ThrowFatalException(CacheFatalError,"UnableToListen");
952 for (p=result; p != (struct addrinfo *) NULL; p=p->ai_next)
957 server_socket=socket(p->ai_family,p->ai_socktype,p->ai_protocol);
958 if (server_socket == -1)
961 status=setsockopt(server_socket,SOL_SOCKET,SO_REUSEADDR,&one,(socklen_t)
965 status=bind(server_socket,p->ai_addr,p->ai_addrlen);
968 (void) close(status);
973 if (p == (struct addrinfo *) NULL)
974 ThrowFatalException(CacheFatalError,"UnableToBind");
975 freeaddrinfo(result);
976 status=listen(server_socket,DPCPendingConnections);
978 ThrowFatalException(CacheFatalError,"UnableToListen");
979 pthread_attr_init(&attributes);
988 length=(socklen_t) sizeof(address);
989 client_socket=accept(server_socket,(struct sockaddr *) &address,&length);
990 if (client_socket == -1)
991 ThrowFatalException(CacheFatalError,"UnableToEstablishConnection");
992 status=pthread_create(&threads,&attributes,DistributePixelCacheClient,
993 (void *) &client_socket);
995 ThrowFatalException(CacheFatalError,"UnableToCreateClientThread");
997 (void) close(server_socket);
999 ThrowFatalException(MissingDelegateError,"distributed pixel cache");
1004 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1008 + G e t D i s t r i b u t e C a c h e F i l e %
1012 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1014 % GetDistributeCacheFile() returns the file associated with this
1015 % DistributeCacheInfo structure.
1017 % The format of the GetDistributeCacheFile method is:
1019 % int GetDistributeCacheFile(const DistributeCacheInfo *server_info)
1021 % A description of each parameter follows:
1023 % o server_info: the distributed cache info.
1026 MagickPrivate int GetDistributeCacheFile(const DistributeCacheInfo *server_info)
1028 assert(server_info != (DistributeCacheInfo *) NULL);
1029 assert(server_info->signature == MagickSignature);
1030 return(server_info->file);
1034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1038 + G e t D i s t r i b u t e C a c h e H o s t n a m e %
1042 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1044 % GetDistributeCacheHostname() returns the hostname associated with this
1045 % DistributeCacheInfo structure.
1047 % The format of the GetDistributeCacheHostname method is:
1049 % const char *GetDistributeCacheHostname(
1050 % const DistributeCacheInfo *server_info)
1052 % A description of each parameter follows:
1054 % o server_info: the distributed cache info.
1057 MagickPrivate const char *GetDistributeCacheHostname(
1058 const DistributeCacheInfo *server_info)
1060 assert(server_info != (DistributeCacheInfo *) NULL);
1061 assert(server_info->signature == MagickSignature);
1062 return(server_info->hostname);
1066 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1070 + G e t D i s t r i b u t e C a c h e P o r t %
1074 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1076 % GetDistributeCachePort() returns the port associated with this
1077 % DistributeCacheInfo structure.
1079 % The format of the GetDistributeCachePort method is:
1081 % int GetDistributeCachePort(const DistributeCacheInfo *server_info)
1083 % A description of each parameter follows:
1085 % o server_info: the distributed cache info.
1088 MagickPrivate int GetDistributeCachePort(const DistributeCacheInfo *server_info)
1090 assert(server_info != (DistributeCacheInfo *) NULL);
1091 assert(server_info->signature == MagickSignature);
1092 return(server_info->port);
1096 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1100 + O p e n D i s t r i b u t e P i x e l C a c h e %
1104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1106 % OpenDistributePixelCache() opens a pixel cache on a remote server.
1108 % The format of the OpenDistributePixelCache method is:
1110 % MagickBooleanType *OpenDistributePixelCache(
1111 % DistributeCacheInfo *server_info,Image *image)
1113 % A description of each parameter follows:
1115 % o server_info: the distributed cache info.
1117 % o image: the image.
1120 MagickPrivate MagickBooleanType OpenDistributePixelCache(
1121 DistributeCacheInfo *server_info,Image *image)
1129 register unsigned char
1133 message[MaxTextExtent];
1136 Open distributed pixel cache.
1138 assert(server_info != (DistributeCacheInfo *) NULL);
1139 assert(server_info->signature == MagickSignature);
1140 assert(image != (Image *) NULL);
1141 assert(image->signature == MagickSignature);
1143 *p++='o'; /* open */
1145 Serialize image attributes (see ValidatePixelCacheMorphology()).
1147 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1148 p+=sizeof(server_info->session_key);
1149 (void) memcpy(p,&image->storage_class,sizeof(image->storage_class));
1150 p+=sizeof(image->storage_class);
1151 (void) memcpy(p,&image->colorspace,sizeof(image->colorspace));
1152 p+=sizeof(image->colorspace);
1153 (void) memcpy(p,&image->alpha_trait,sizeof(image->alpha_trait));
1154 p+=sizeof(image->alpha_trait);
1155 (void) memcpy(p,&image->mask,sizeof(image->mask));
1156 p+=sizeof(image->mask);
1157 (void) memcpy(p,&image->columns,sizeof(image->columns));
1158 p+=sizeof(image->columns);
1159 (void) memcpy(p,&image->rows,sizeof(image->rows));
1160 p+=sizeof(image->rows);
1161 (void) memcpy(p,&image->number_channels,sizeof(image->number_channels));
1162 p+=sizeof(image->number_channels);
1163 (void) memcpy(p,image->channel_map,MaxPixelChannels*
1164 sizeof(*image->channel_map));
1165 p+=MaxPixelChannels*sizeof(*image->channel_map);
1166 (void) memcpy(p,&image->metacontent_extent,sizeof(image->metacontent_extent));
1167 p+=sizeof(image->metacontent_extent);
1168 count=dpc_send(server_info->file,p-message,message);
1169 if (count != (MagickOffsetType) (p-message))
1170 return(MagickFalse);
1172 count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status);
1173 if (count != (MagickOffsetType) sizeof(status))
1174 return(MagickFalse);
1179 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1183 + R e a d D i s t r i b u t e P i x e l C a c h e M e t a c o n t e n t %
1187 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1189 % ReadDistributePixelCacheMetacontents() reads metacontent from the specified
1190 % region of the distributed pixel cache.
1192 % The format of the ReadDistributePixelCacheMetacontents method is:
1194 % MagickOffsetType ReadDistributePixelCacheMetacontents(
1195 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1196 % const MagickSizeType length,unsigned char *metacontent)
1198 % A description of each parameter follows:
1200 % o server_info: the distributed cache info.
1202 % o image: the image.
1204 % o region: read the metacontent from this region of the image.
1206 % o length: the length in bytes of the metacontent.
1208 % o metacontent: read these metacontent from the pixel cache.
1211 MagickPrivate MagickOffsetType ReadDistributePixelCacheMetacontent(
1212 DistributeCacheInfo *server_info,const RectangleInfo *region,
1213 const MagickSizeType length,unsigned char *metacontent)
1218 register unsigned char
1222 message[MaxTextExtent];
1225 Read distributed pixel cache metacontent.
1227 assert(server_info != (DistributeCacheInfo *) NULL);
1228 assert(server_info->signature == MagickSignature);
1229 assert(region != (RectangleInfo *) NULL);
1230 assert(metacontent != (unsigned char *) NULL);
1231 if (length > (MagickSizeType) SSIZE_MAX)
1235 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1236 p+=sizeof(server_info->session_key);
1237 (void) memcpy(p,®ion->width,sizeof(region->width));
1238 p+=sizeof(region->width);
1239 (void) memcpy(p,®ion->height,sizeof(region->height));
1240 p+=sizeof(region->height);
1241 (void) memcpy(p,®ion->x,sizeof(region->x));
1242 p+=sizeof(region->x);
1243 (void) memcpy(p,®ion->y,sizeof(region->y));
1244 p+=sizeof(region->y);
1245 (void) memcpy(p,&length,sizeof(length));
1247 count=dpc_send(server_info->file,p-message,message);
1248 if (count != (MagickOffsetType) (p-message))
1250 return(dpc_read(server_info->file,length,metacontent));
1254 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1258 + R e a d D i s t r i b u t e P i x e l C a c h e P i x e l s %
1262 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1264 % ReadDistributePixelCachePixels() reads pixels from the specified region of
1265 % the distributed pixel cache.
1267 % The format of the ReadDistributePixelCachePixels method is:
1269 % MagickOffsetType ReadDistributePixelCachePixels(
1270 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1271 % const MagickSizeType length,unsigned char *pixels)
1273 % A description of each parameter follows:
1275 % o server_info: the distributed cache info.
1277 % o image: the image.
1279 % o region: read the pixels from this region of the image.
1281 % o length: the length in bytes of the pixels.
1283 % o pixels: read these pixels from the pixel cache.
1286 MagickPrivate MagickOffsetType ReadDistributePixelCachePixels(
1287 DistributeCacheInfo *server_info,const RectangleInfo *region,
1288 const MagickSizeType length,unsigned char *pixels)
1293 register unsigned char
1297 message[MaxTextExtent];
1300 Read distributed pixel cache pixels.
1302 assert(server_info != (DistributeCacheInfo *) NULL);
1303 assert(server_info->signature == MagickSignature);
1304 assert(region != (RectangleInfo *) NULL);
1305 assert(pixels != (unsigned char *) NULL);
1306 if (length > (MagickSizeType) SSIZE_MAX)
1310 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1311 p+=sizeof(server_info->session_key);
1312 (void) memcpy(p,®ion->width,sizeof(region->width));
1313 p+=sizeof(region->width);
1314 (void) memcpy(p,®ion->height,sizeof(region->height));
1315 p+=sizeof(region->height);
1316 (void) memcpy(p,®ion->x,sizeof(region->x));
1317 p+=sizeof(region->x);
1318 (void) memcpy(p,®ion->y,sizeof(region->y));
1319 p+=sizeof(region->y);
1320 (void) memcpy(p,&length,sizeof(length));
1322 count=dpc_send(server_info->file,p-message,message);
1323 if (count != (MagickOffsetType) (p-message))
1325 return(dpc_read(server_info->file,length,pixels));
1329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1333 + 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 %
1337 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1339 % RelinquishDistributePixelCache() frees resources acquired with
1340 % OpenDistributePixelCache().
1342 % The format of the RelinquishDistributePixelCache method is:
1344 % MagickBooleanType RelinquishDistributePixelCache(
1345 % DistributeCacheInfo *server_info)
1347 % A description of each parameter follows:
1349 % o server_info: the distributed cache info.
1352 MagickPrivate MagickBooleanType RelinquishDistributePixelCache(
1353 DistributeCacheInfo *server_info)
1361 register unsigned char
1365 message[MaxTextExtent];
1368 Delete distributed pixel cache.
1370 assert(server_info != (DistributeCacheInfo *) NULL);
1371 assert(server_info->signature == MagickSignature);
1374 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1375 p+=sizeof(server_info->session_key);
1376 count=dpc_send(server_info->file,p-message,message);
1377 if (count != (MagickOffsetType) (p-message))
1378 return(MagickFalse);
1379 count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status);
1380 if (count != (MagickOffsetType) sizeof(status))
1381 return(MagickFalse);
1386 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1390 + 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 M e t a c o n t e n t %
1394 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1396 % WriteDistributePixelCacheMetacontents() writes image metacontent to the
1397 % specified region of the distributed pixel cache.
1399 % The format of the WriteDistributePixelCacheMetacontents method is:
1401 % MagickOffsetType WriteDistributePixelCacheMetacontents(
1402 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1403 % const MagickSizeType length,const unsigned char *metacontent)
1405 % A description of each parameter follows:
1407 % o server_info: the distributed cache info.
1409 % o image: the image.
1411 % o region: write the metacontent to this region of the image.
1413 % o length: the length in bytes of the metacontent.
1415 % o metacontent: write these metacontent to the pixel cache.
1418 MagickPrivate MagickOffsetType WriteDistributePixelCacheMetacontent(
1419 DistributeCacheInfo *server_info,const RectangleInfo *region,
1420 const MagickSizeType length,const unsigned char *metacontent)
1425 register unsigned char
1429 message[MaxTextExtent];
1432 Write distributed pixel cache metacontent.
1434 assert(server_info != (DistributeCacheInfo *) NULL);
1435 assert(server_info->signature == MagickSignature);
1436 assert(region != (RectangleInfo *) NULL);
1437 assert(metacontent != (unsigned char *) NULL);
1438 if (length > (MagickSizeType) SSIZE_MAX)
1442 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1443 p+=sizeof(server_info->session_key);
1444 (void) memcpy(p,®ion->width,sizeof(region->width));
1445 p+=sizeof(region->width);
1446 (void) memcpy(p,®ion->height,sizeof(region->height));
1447 p+=sizeof(region->height);
1448 (void) memcpy(p,®ion->x,sizeof(region->x));
1449 p+=sizeof(region->x);
1450 (void) memcpy(p,®ion->y,sizeof(region->y));
1451 p+=sizeof(region->y);
1452 (void) memcpy(p,&length,sizeof(length));
1454 count=dpc_send(server_info->file,p-message,message);
1455 if (count != (MagickOffsetType) (p-message))
1457 return(dpc_send(server_info->file,length,metacontent));
1461 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1465 + 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 P i x e l s %
1469 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1471 % WriteDistributePixelCachePixels() writes image pixels to the specified
1472 % region of the distributed pixel cache.
1474 % The format of the WriteDistributePixelCachePixels method is:
1476 % MagickBooleanType WriteDistributePixelCachePixels(
1477 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1478 % const MagickSizeType length,const unsigned char *pixels)
1480 % A description of each parameter follows:
1482 % o server_info: the distributed cache info.
1484 % o image: the image.
1486 % o region: write the pixels to this region of the image.
1488 % o length: the length in bytes of the pixels.
1490 % o pixels: write these pixels to the pixel cache.
1493 MagickPrivate MagickOffsetType WriteDistributePixelCachePixels(
1494 DistributeCacheInfo *server_info,const RectangleInfo *region,
1495 const MagickSizeType length,const unsigned char *pixels)
1500 register unsigned char
1504 message[MaxTextExtent];
1507 Write distributed pixel cache pixels.
1509 assert(server_info != (DistributeCacheInfo *) NULL);
1510 assert(server_info->signature == MagickSignature);
1511 assert(region != (RectangleInfo *) NULL);
1512 assert(pixels != (const unsigned char *) NULL);
1513 if (length > (MagickSizeType) SSIZE_MAX)
1517 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1518 p+=sizeof(server_info->session_key);
1519 (void) memcpy(p,®ion->width,sizeof(region->width));
1520 p+=sizeof(region->width);
1521 (void) memcpy(p,®ion->height,sizeof(region->height));
1522 p+=sizeof(region->height);
1523 (void) memcpy(p,®ion->x,sizeof(region->x));
1524 p+=sizeof(region->x);
1525 (void) memcpy(p,®ion->y,sizeof(region->y));
1526 p+=sizeof(region->y);
1527 (void) memcpy(p,&length,sizeof(length));
1529 count=dpc_send(server_info->file,p-message,message);
1530 if (count != (MagickOffsetType) (p-message))
1532 return(dpc_send(server_info->file,length,pixels));