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-2014 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/nt-base-private.h"
67 #include "MagickCore/pixel.h"
68 #include "MagickCore/policy.h"
69 #include "MagickCore/random_.h"
70 #include "MagickCore/registry.h"
71 #include "MagickCore/splay-tree.h"
72 #include "MagickCore/string_.h"
73 #include "MagickCore/string-private.h"
74 #include "MagickCore/version.h"
75 #include "MagickCore/version-private.h"
76 #if defined(MAGICKCORE_HAVE_SOCKET) && defined(MAGICKCORE_THREAD_SUPPORT)
77 #include <netinet/in.h>
79 #include <sys/socket.h>
80 #include <arpa/inet.h>
84 #define send(file,buffer,length,flags) 0
85 #define recv(file,buffer,length,flags) 0
91 #define DPCHostname "127.0.0.1"
92 #define DPCPendingConnections 10
94 #define DPCSessionKeyLength 8
96 # define MSG_NOSIGNAL 0
100 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
104 + 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 %
108 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
110 % AcquireDistributeCacheInfo() allocates the DistributeCacheInfo structure.
112 % The format of the AcquireDistributeCacheInfo method is:
114 % DistributeCacheInfo *AcquireDistributeCacheInfo(ExceptionInfo *exception)
116 % A description of each parameter follows:
118 % o exception: return any errors or warnings in this structure.
122 static inline MagickSizeType MagickMin(const MagickSizeType x,
123 const MagickSizeType y)
130 static inline MagickOffsetType dpc_read(int file,const MagickSizeType length,
131 unsigned char *restrict message)
133 register MagickOffsetType
139 #if !defined(MAGICKCORE_HAVE_SOCKET) || !defined(MAGICKCORE_THREAD_SUPPORT)
140 magick_unreferenced(file);
141 magick_unreferenced(message);
145 for (i=0; i < (MagickOffsetType) length; i+=count)
147 count=recv(file,message+i,(size_t) MagickMin(length-i,(MagickSizeType)
159 static int ConnectPixelCacheServer(const char *hostname,const int port,
160 size_t *session_key,ExceptionInfo *exception)
162 #if defined(MAGICKCORE_HAVE_SOCKET) && defined(MAGICKCORE_THREAD_SUPPORT)
164 service[MaxTextExtent];
181 secret[MaxTextExtent];
184 Connect to distributed pixel cache and get session key.
187 shared_secret=GetPolicyValue("shared-secret");
188 if (shared_secret == (const char *) NULL)
190 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
191 "DistributedPixelCache","'%s'","shared secret expected");
194 (void) ResetMagickMemory(&hint,0,sizeof(hint));
195 hint.ai_family=AF_INET;
196 hint.ai_socktype=SOCK_STREAM;
197 hint.ai_flags=AI_PASSIVE;
198 (void) FormatLocaleString(service,MaxTextExtent,"%d",port);
199 status=getaddrinfo(hostname,service,&hint,&result);
202 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
203 "DistributedPixelCache","'%s'",hostname);
206 client_socket=socket(result->ai_family,result->ai_socktype,
207 result->ai_protocol);
208 if (client_socket == -1)
210 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
211 "DistributedPixelCache","'%s'",hostname);
214 status=connect(client_socket,result->ai_addr,result->ai_addrlen);
217 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
218 "DistributedPixelCache","'%s'",hostname);
221 count=recv(client_socket,secret,MaxTextExtent,0);
227 nonce=AcquireStringInfo(count);
228 (void) memcpy(GetStringInfoDatum(nonce),secret,(size_t) count);
229 *session_key=GetMagickSignature(nonce);
230 nonce=DestroyStringInfo(nonce);
232 if (*session_key == 0)
234 close(client_socket);
237 return(client_socket);
239 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
240 "DelegateLibrarySupportNotBuiltIn","distributed pixel cache");
245 static char *GetHostname(int *port,ExceptionInfo *exception)
262 Parse host list (e.g. 192.168.100.1:6668,192.168.100.2:6668).
264 hosts=(char *) GetImageRegistry(StringRegistryType,"cache:hosts",
266 if (hosts == (char *) NULL)
269 return(AcquireString(DPCHostname));
271 (void) SubstituteString(&hosts,","," ");
272 hostlist=StringToArgv(hosts,&argc);
273 hosts=DestroyString(hosts);
274 if (hostlist == (char **) NULL)
277 return(AcquireString(DPCHostname));
279 hosts=AcquireString(hostlist[(id++ % (argc-1))+1]);
280 for (i=0; i < (ssize_t) argc; i++)
281 hostlist[i]=DestroyString(hostlist[i]);
282 hostlist=(char **) RelinquishMagickMemory(hostlist);
283 (void) SubstituteString(&hosts,":"," ");
284 hostlist=StringToArgv(hosts,&argc);
285 if (hostlist == (char **) NULL)
288 return(AcquireString(DPCHostname));
290 host=AcquireString(hostlist[1]);
291 if (hostlist[2] == (char *) NULL)
294 *port=StringToLong(hostlist[2]);
295 for (i=0; i < (ssize_t) argc; i++)
296 hostlist[i]=DestroyString(hostlist[i]);
297 hostlist=(char **) RelinquishMagickMemory(hostlist);
301 MagickPrivate DistributeCacheInfo *AcquireDistributeCacheInfo(
302 ExceptionInfo *exception)
314 Connect to the distributed pixel cache server.
316 server_info=(DistributeCacheInfo *) AcquireMagickMemory(sizeof(*server_info));
317 if (server_info == (DistributeCacheInfo *) NULL)
318 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
319 (void) ResetMagickMemory(server_info,0,sizeof(*server_info));
320 server_info->signature=MagickSignature;
322 hostname=GetHostname(&server_info->port,exception);
324 server_info->file=ConnectPixelCacheServer(hostname,server_info->port,
325 &session_key,exception);
326 server_info->session_key=session_key;
327 (void) CopyMagickString(server_info->hostname,hostname,MaxTextExtent);
328 hostname=DestroyString(hostname);
329 if (server_info->file == -1)
330 server_info=DestroyDistributeCacheInfo(server_info);
331 server_info->debug=IsEventLogging();
336 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
340 + 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 %
344 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
346 % DestroyDistributeCacheInfo() deallocates memory associated with an
347 % DistributeCacheInfo structure.
349 % The format of the DestroyDistributeCacheInfo method is:
351 % DistributeCacheInfo *DestroyDistributeCacheInfo(
352 % DistributeCacheInfo *server_info)
354 % A description of each parameter follows:
356 % o server_info: the distributed cache info.
359 MagickPrivate DistributeCacheInfo *DestroyDistributeCacheInfo(
360 DistributeCacheInfo *server_info)
362 assert(server_info != (DistributeCacheInfo *) NULL);
363 assert(server_info->signature == MagickSignature);
364 if (server_info->file > 0)
365 (void) close(server_info->file);
366 server_info->signature=(~MagickSignature);
367 server_info=(DistributeCacheInfo *) RelinquishMagickMemory(server_info);
372 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
376 + 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 %
380 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
382 % DistributePixelCacheServer() waits on the specified port for commands to
383 % create, read, update, or destroy a pixel cache.
385 % The format of the DistributePixelCacheServer() method is:
387 % void DistributePixelCacheServer(const int port)
389 % A description of each parameter follows:
391 % o port: connect the distributed pixel cache at this port.
393 % o exception: return any errors or warnings in this structure.
397 static MagickBooleanType DestroyDistributeCache(SplayTreeInfo *registry,
398 int magick_unused(file),const size_t session_key)
401 Destroy distributed pixel cache.
403 magick_unreferenced(file);
404 return(DeleteNodeFromSplayTree(registry,(const void *) session_key));
407 static inline MagickOffsetType dpc_send(int file,const MagickSizeType length,
408 const unsigned char *restrict message)
413 register MagickOffsetType
416 #if !defined(MAGICKCORE_HAVE_SOCKET) || !defined(MAGICKCORE_THREAD_SUPPORT)
417 magick_unreferenced(file);
418 magick_unreferenced(message);
422 Ensure a complete message is sent.
425 for (i=0; i < (MagickOffsetType) length; i+=count)
427 count=(MagickOffsetType) send(file,message+i,(size_t) MagickMin(length-i,
428 (MagickSizeType) SSIZE_MAX),MSG_NOSIGNAL);
439 static MagickBooleanType OpenDistributeCache(SplayTreeInfo *registry,
440 int file,const size_t session_key,ExceptionInfo *exception)
454 register unsigned char
458 message[MaxTextExtent];
461 Open distributed pixel cache.
463 image=AcquireImage((ImageInfo *) NULL,exception);
464 if (image == (Image *) NULL)
466 length=sizeof(image->storage_class)+sizeof(image->colorspace)+
467 sizeof(image->alpha_trait)+sizeof(image->read_mask)+
468 sizeof(image->write_mask)+sizeof(image->columns)+sizeof(image->rows)+
469 sizeof(image->number_channels)+MaxPixelChannels*sizeof(*image->channel_map)+
470 sizeof(image->metacontent_extent);
471 count=dpc_read(file,length,message);
472 if (count != (MagickOffsetType) length)
475 Deserialize the image attributes.
478 (void) memcpy(&image->storage_class,p,sizeof(image->storage_class));
479 p+=sizeof(image->storage_class);
480 (void) memcpy(&image->colorspace,p,sizeof(image->colorspace));
481 p+=sizeof(image->colorspace);
482 (void) memcpy(&image->alpha_trait,p,sizeof(image->alpha_trait));
483 p+=sizeof(image->alpha_trait);
484 (void) memcpy(&image->read_mask,p,sizeof(image->read_mask));
485 p+=sizeof(image->read_mask);
486 (void) memcpy(&image->write_mask,p,sizeof(image->write_mask));
487 p+=sizeof(image->write_mask);
488 (void) memcpy(&image->columns,p,sizeof(image->columns));
489 p+=sizeof(image->columns);
490 (void) memcpy(&image->rows,p,sizeof(image->rows));
491 p+=sizeof(image->rows);
492 (void) memcpy(&image->number_channels,p,sizeof(image->number_channels));
493 p+=sizeof(image->number_channels);
494 (void) memcpy(image->channel_map,p,MaxPixelChannels*
495 sizeof(*image->channel_map));
496 p+=MaxPixelChannels*sizeof(*image->channel_map);
497 (void) memcpy(&image->metacontent_extent,p,sizeof(image->metacontent_extent));
498 p+=sizeof(image->metacontent_extent);
499 if (SyncImagePixelCache(image,exception) == MagickFalse)
501 status=AddValueToSplayTree(registry,(const void *) session_key,image);
505 static MagickBooleanType ReadDistributeCacheMetacontent(SplayTreeInfo *registry,
506 int file,const size_t session_key,ExceptionInfo *exception)
523 register const Quantum
526 register unsigned char
530 message[MaxTextExtent];
533 Read distributed pixel cache metacontent.
535 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
536 if (image == (Image *) NULL)
538 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
539 sizeof(region.y)+sizeof(length);
540 count=dpc_read(file,length,message);
541 if (count != (MagickOffsetType) length)
544 (void) memcpy(®ion.width,q,sizeof(region.width));
545 q+=sizeof(region.width);
546 (void) memcpy(®ion.height,q,sizeof(region.height));
547 q+=sizeof(region.height);
548 (void) memcpy(®ion.x,q,sizeof(region.x));
550 (void) memcpy(®ion.y,q,sizeof(region.y));
552 (void) memcpy(&length,q,sizeof(length));
554 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
556 if (p == (const Quantum *) NULL)
558 metacontent=(const unsigned char *) GetVirtualMetacontent(image);
559 count=dpc_send(file,length,metacontent);
560 if (count != (MagickOffsetType) length)
565 static MagickBooleanType ReadDistributeCachePixels(SplayTreeInfo *registry,
566 int file,const size_t session_key,ExceptionInfo *exception)
580 register const Quantum
583 register unsigned char
587 message[MaxTextExtent];
590 Read distributed pixel cache pixels.
592 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
593 if (image == (Image *) NULL)
595 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
596 sizeof(region.y)+sizeof(length);
597 count=dpc_read(file,length,message);
598 if (count != (MagickOffsetType) length)
601 (void) memcpy(®ion.width,q,sizeof(region.width));
602 q+=sizeof(region.width);
603 (void) memcpy(®ion.height,q,sizeof(region.height));
604 q+=sizeof(region.height);
605 (void) memcpy(®ion.x,q,sizeof(region.x));
607 (void) memcpy(®ion.y,q,sizeof(region.y));
609 (void) memcpy(&length,q,sizeof(length));
611 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
613 if (p == (const Quantum *) NULL)
615 count=dpc_send(file,length,(unsigned char *) p);
616 if (count != (MagickOffsetType) length)
621 static void *RelinquishImageRegistry(void *image)
623 return((void *) DestroyImageList((Image *) image));
626 static MagickBooleanType WriteDistributeCacheMetacontent(
627 SplayTreeInfo *registry,int file,const size_t session_key,
628 ExceptionInfo *exception)
645 register unsigned char
649 message[MaxTextExtent],
653 Write distributed pixel cache metacontent.
655 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
656 if (image == (Image *) NULL)
658 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
659 sizeof(region.y)+sizeof(length);
660 count=dpc_read(file,length,message);
661 if (count != (MagickOffsetType) length)
664 (void) memcpy(®ion.width,p,sizeof(region.width));
665 p+=sizeof(region.width);
666 (void) memcpy(®ion.height,p,sizeof(region.height));
667 p+=sizeof(region.height);
668 (void) memcpy(®ion.x,p,sizeof(region.x));
670 (void) memcpy(®ion.y,p,sizeof(region.y));
672 (void) memcpy(&length,p,sizeof(length));
674 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
676 if (q == (Quantum *) NULL)
678 metacontent=(unsigned char *) GetAuthenticMetacontent(image);
679 count=dpc_read(file,length,metacontent);
680 if (count != (MagickOffsetType) length)
682 return(SyncAuthenticPixels(image,exception));
685 static MagickBooleanType WriteDistributeCachePixels(SplayTreeInfo *registry,
686 int file,const size_t session_key,ExceptionInfo *exception)
703 register unsigned char
707 message[MaxTextExtent];
710 Write distributed pixel cache pixels.
712 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
713 if (image == (Image *) NULL)
715 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
716 sizeof(region.y)+sizeof(length);
717 count=dpc_read(file,length,message);
718 if (count != (MagickOffsetType) length)
721 (void) memcpy(®ion.width,p,sizeof(region.width));
722 p+=sizeof(region.width);
723 (void) memcpy(®ion.height,p,sizeof(region.height));
724 p+=sizeof(region.height);
725 (void) memcpy(®ion.x,p,sizeof(region.x));
727 (void) memcpy(®ion.y,p,sizeof(region.y));
729 (void) memcpy(&length,p,sizeof(length));
731 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
733 if (q == (Quantum *) NULL)
735 count=dpc_read(file,length,(unsigned char *) q);
736 if (count != (MagickOffsetType) length)
738 return(SyncAuthenticPixels(image,exception));
741 static void *DistributePixelCacheClient(void *socket)
758 register unsigned char
776 session[2*MaxTextExtent];
779 Distributed pixel cache client.
781 shared_secret=GetPolicyValue("shared-secret");
782 if (shared_secret == (const char *) NULL)
783 ThrowFatalException(CacheFatalError,"shared secret expected");
785 (void) CopyMagickString((char *) p,shared_secret,MaxTextExtent);
786 p+=strlen(shared_secret);
787 random_info=AcquireRandomInfo();
788 secret=GetRandomKey(random_info,DPCSessionKeyLength);
789 (void) memcpy(p,GetStringInfoDatum(secret),DPCSessionKeyLength);
790 session_key=GetMagickSignature(secret);
791 random_info=DestroyRandomInfo(random_info);
792 exception=AcquireExceptionInfo();
793 registry=NewSplayTree((int (*)(const void *,const void *)) NULL,
794 (void *(*)(void *)) NULL,RelinquishImageRegistry);
795 client_socket=(*(int *) socket);
796 count=dpc_send(client_socket,DPCSessionKeyLength,GetStringInfoDatum(secret));
797 secret=DestroyStringInfo(secret);
800 count=dpc_read(client_socket,1,(unsigned char *) &command);
803 count=dpc_read(client_socket,sizeof(key),(unsigned char *) &key);
804 if ((count != (MagickOffsetType) sizeof(key)) || (key != session_key))
811 status=OpenDistributeCache(registry,client_socket,session_key,
813 count=dpc_send(client_socket,sizeof(status),(unsigned char *) &status);
818 status=ReadDistributeCachePixels(registry,client_socket,session_key,
824 status=ReadDistributeCacheMetacontent(registry,client_socket,
825 session_key,exception);
830 status=WriteDistributeCachePixels(registry,client_socket,session_key,
836 status=WriteDistributeCacheMetacontent(registry,client_socket,
837 session_key,exception);
842 status=DestroyDistributeCache(registry,client_socket,session_key);
848 if (status == MagickFalse)
853 count=dpc_send(client_socket,sizeof(status),(unsigned char *) &status);
854 (void) close(client_socket);
855 exception=DestroyExceptionInfo(exception);
856 registry=DestroySplayTree(registry);
857 return((void *) NULL);
860 MagickExport void DistributePixelCacheServer(const int port,
861 ExceptionInfo *exception)
863 #if defined(MAGICKCORE_HAVE_SOCKET) && defined(MAGICKCORE_THREAD_SUPPORT)
865 service[MaxTextExtent];
877 register struct addrinfo
888 Launch distributed pixel cache server.
890 assert(exception != (ExceptionInfo *) NULL);
891 assert(exception->signature == MagickSignature);
892 (void) ResetMagickMemory(&hint,0,sizeof(hint));
893 hint.ai_family=AF_INET;
894 hint.ai_socktype=SOCK_STREAM;
895 hint.ai_flags=AI_PASSIVE;
896 (void) FormatLocaleString(service,MaxTextExtent,"%d",port);
897 status=getaddrinfo((const char *) NULL,service,&hint,&result);
899 ThrowFatalException(CacheFatalError,"UnableToListen");
901 for (p=result; p != (struct addrinfo *) NULL; p=p->ai_next)
906 server_socket=socket(p->ai_family,p->ai_socktype,p->ai_protocol);
907 if (server_socket == -1)
910 status=setsockopt(server_socket,SOL_SOCKET,SO_REUSEADDR,&one,(socklen_t)
914 status=bind(server_socket,p->ai_addr,p->ai_addrlen);
917 (void) close(status);
922 if (p == (struct addrinfo *) NULL)
923 ThrowFatalException(CacheFatalError,"UnableToBind");
924 freeaddrinfo(result);
925 status=listen(server_socket,DPCPendingConnections);
927 ThrowFatalException(CacheFatalError,"UnableToListen");
928 pthread_attr_init(&attributes);
937 length=(socklen_t) sizeof(address);
938 client_socket=accept(server_socket,(struct sockaddr *) &address,&length);
939 if (client_socket == -1)
940 ThrowFatalException(CacheFatalError,"UnableToEstablishConnection");
941 status=pthread_create(&threads,&attributes,DistributePixelCacheClient,
942 (void *) &client_socket);
944 ThrowFatalException(CacheFatalError,"UnableToCreateClientThread");
946 (void) close(server_socket);
948 ThrowFatalException(MissingDelegateError,"distributed pixel cache");
953 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
957 + G e t D i s t r i b u t e C a c h e F i l e %
961 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
963 % GetDistributeCacheFile() returns the file associated with this
964 % DistributeCacheInfo structure.
966 % The format of the GetDistributeCacheFile method is:
968 % int GetDistributeCacheFile(const DistributeCacheInfo *server_info)
970 % A description of each parameter follows:
972 % o server_info: the distributed cache info.
975 MagickPrivate int GetDistributeCacheFile(const DistributeCacheInfo *server_info)
977 assert(server_info != (DistributeCacheInfo *) NULL);
978 assert(server_info->signature == MagickSignature);
979 return(server_info->file);
983 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
987 + 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 %
991 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
993 % GetDistributeCacheHostname() returns the hostname associated with this
994 % DistributeCacheInfo structure.
996 % The format of the GetDistributeCacheHostname method is:
998 % const char *GetDistributeCacheHostname(
999 % const DistributeCacheInfo *server_info)
1001 % A description of each parameter follows:
1003 % o server_info: the distributed cache info.
1006 MagickPrivate const char *GetDistributeCacheHostname(
1007 const DistributeCacheInfo *server_info)
1009 assert(server_info != (DistributeCacheInfo *) NULL);
1010 assert(server_info->signature == MagickSignature);
1011 return(server_info->hostname);
1015 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1019 + G e t D i s t r i b u t e C a c h e P o r t %
1023 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1025 % GetDistributeCachePort() returns the port associated with this
1026 % DistributeCacheInfo structure.
1028 % The format of the GetDistributeCachePort method is:
1030 % int GetDistributeCachePort(const DistributeCacheInfo *server_info)
1032 % A description of each parameter follows:
1034 % o server_info: the distributed cache info.
1037 MagickPrivate int GetDistributeCachePort(const DistributeCacheInfo *server_info)
1039 assert(server_info != (DistributeCacheInfo *) NULL);
1040 assert(server_info->signature == MagickSignature);
1041 return(server_info->port);
1045 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1049 + O p e n D i s t r i b u t e P i x e l C a c h e %
1053 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1055 % OpenDistributePixelCache() opens a pixel cache on a remote server.
1057 % The format of the OpenDistributePixelCache method is:
1059 % MagickBooleanType *OpenDistributePixelCache(
1060 % DistributeCacheInfo *server_info,Image *image)
1062 % A description of each parameter follows:
1064 % o server_info: the distributed cache info.
1066 % o image: the image.
1069 MagickPrivate MagickBooleanType OpenDistributePixelCache(
1070 DistributeCacheInfo *server_info,Image *image)
1078 register unsigned char
1082 message[MaxTextExtent];
1085 Open distributed pixel cache.
1087 assert(server_info != (DistributeCacheInfo *) NULL);
1088 assert(server_info->signature == MagickSignature);
1089 assert(image != (Image *) NULL);
1090 assert(image->signature == MagickSignature);
1092 *p++='o'; /* open */
1094 Serialize image attributes (see ValidatePixelCacheMorphology()).
1096 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1097 p+=sizeof(server_info->session_key);
1098 (void) memcpy(p,&image->storage_class,sizeof(image->storage_class));
1099 p+=sizeof(image->storage_class);
1100 (void) memcpy(p,&image->colorspace,sizeof(image->colorspace));
1101 p+=sizeof(image->colorspace);
1102 (void) memcpy(p,&image->alpha_trait,sizeof(image->alpha_trait));
1103 p+=sizeof(image->alpha_trait);
1104 (void) memcpy(p,&image->read_mask,sizeof(image->read_mask));
1105 p+=sizeof(image->read_mask);
1106 (void) memcpy(p,&image->write_mask,sizeof(image->write_mask));
1107 p+=sizeof(image->write_mask);
1108 (void) memcpy(p,&image->columns,sizeof(image->columns));
1109 p+=sizeof(image->columns);
1110 (void) memcpy(p,&image->rows,sizeof(image->rows));
1111 p+=sizeof(image->rows);
1112 (void) memcpy(p,&image->number_channels,sizeof(image->number_channels));
1113 p+=sizeof(image->number_channels);
1114 (void) memcpy(p,image->channel_map,MaxPixelChannels*
1115 sizeof(*image->channel_map));
1116 p+=MaxPixelChannels*sizeof(*image->channel_map);
1117 (void) memcpy(p,&image->metacontent_extent,sizeof(image->metacontent_extent));
1118 p+=sizeof(image->metacontent_extent);
1119 count=dpc_send(server_info->file,p-message,message);
1120 if (count != (MagickOffsetType) (p-message))
1121 return(MagickFalse);
1123 count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status);
1124 if (count != (MagickOffsetType) sizeof(status))
1125 return(MagickFalse);
1130 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1134 + 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 %
1138 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1140 % ReadDistributePixelCacheMetacontents() reads metacontent from the specified
1141 % region of the distributed pixel cache.
1143 % The format of the ReadDistributePixelCacheMetacontents method is:
1145 % MagickOffsetType ReadDistributePixelCacheMetacontents(
1146 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1147 % const MagickSizeType length,unsigned char *metacontent)
1149 % A description of each parameter follows:
1151 % o server_info: the distributed cache info.
1153 % o image: the image.
1155 % o region: read the metacontent from this region of the image.
1157 % o length: the length in bytes of the metacontent.
1159 % o metacontent: read these metacontent from the pixel cache.
1162 MagickPrivate MagickOffsetType ReadDistributePixelCacheMetacontent(
1163 DistributeCacheInfo *server_info,const RectangleInfo *region,
1164 const MagickSizeType length,unsigned char *metacontent)
1169 register unsigned char
1173 message[MaxTextExtent];
1176 Read distributed pixel cache metacontent.
1178 assert(server_info != (DistributeCacheInfo *) NULL);
1179 assert(server_info->signature == MagickSignature);
1180 assert(region != (RectangleInfo *) NULL);
1181 assert(metacontent != (unsigned char *) NULL);
1182 if (length > (MagickSizeType) SSIZE_MAX)
1186 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1187 p+=sizeof(server_info->session_key);
1188 (void) memcpy(p,®ion->width,sizeof(region->width));
1189 p+=sizeof(region->width);
1190 (void) memcpy(p,®ion->height,sizeof(region->height));
1191 p+=sizeof(region->height);
1192 (void) memcpy(p,®ion->x,sizeof(region->x));
1193 p+=sizeof(region->x);
1194 (void) memcpy(p,®ion->y,sizeof(region->y));
1195 p+=sizeof(region->y);
1196 (void) memcpy(p,&length,sizeof(length));
1198 count=dpc_send(server_info->file,p-message,message);
1199 if (count != (MagickOffsetType) (p-message))
1201 return(dpc_read(server_info->file,length,metacontent));
1205 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1209 + 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 %
1213 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1215 % ReadDistributePixelCachePixels() reads pixels from the specified region of
1216 % the distributed pixel cache.
1218 % The format of the ReadDistributePixelCachePixels method is:
1220 % MagickOffsetType ReadDistributePixelCachePixels(
1221 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1222 % const MagickSizeType length,unsigned char *restrict pixels)
1224 % A description of each parameter follows:
1226 % o server_info: the distributed cache info.
1228 % o image: the image.
1230 % o region: read the pixels from this region of the image.
1232 % o length: the length in bytes of the pixels.
1234 % o pixels: read these pixels from the pixel cache.
1237 MagickPrivate MagickOffsetType ReadDistributePixelCachePixels(
1238 DistributeCacheInfo *server_info,const RectangleInfo *region,
1239 const MagickSizeType length,unsigned char *restrict pixels)
1244 register unsigned char
1248 message[MaxTextExtent];
1251 Read distributed pixel cache pixels.
1253 assert(server_info != (DistributeCacheInfo *) NULL);
1254 assert(server_info->signature == MagickSignature);
1255 assert(region != (RectangleInfo *) NULL);
1256 assert(pixels != (unsigned char *) NULL);
1257 if (length > (MagickSizeType) SSIZE_MAX)
1261 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1262 p+=sizeof(server_info->session_key);
1263 (void) memcpy(p,®ion->width,sizeof(region->width));
1264 p+=sizeof(region->width);
1265 (void) memcpy(p,®ion->height,sizeof(region->height));
1266 p+=sizeof(region->height);
1267 (void) memcpy(p,®ion->x,sizeof(region->x));
1268 p+=sizeof(region->x);
1269 (void) memcpy(p,®ion->y,sizeof(region->y));
1270 p+=sizeof(region->y);
1271 (void) memcpy(p,&length,sizeof(length));
1273 count=dpc_send(server_info->file,p-message,message);
1274 if (count != (MagickOffsetType) (p-message))
1276 return(dpc_read(server_info->file,length,pixels));
1280 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1284 + 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 %
1288 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1290 % RelinquishDistributePixelCache() frees resources acquired with
1291 % OpenDistributePixelCache().
1293 % The format of the RelinquishDistributePixelCache method is:
1295 % MagickBooleanType RelinquishDistributePixelCache(
1296 % DistributeCacheInfo *server_info)
1298 % A description of each parameter follows:
1300 % o server_info: the distributed cache info.
1303 MagickPrivate MagickBooleanType RelinquishDistributePixelCache(
1304 DistributeCacheInfo *server_info)
1312 register unsigned char
1316 message[MaxTextExtent];
1319 Delete distributed pixel cache.
1321 assert(server_info != (DistributeCacheInfo *) NULL);
1322 assert(server_info->signature == MagickSignature);
1325 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1326 p+=sizeof(server_info->session_key);
1327 count=dpc_send(server_info->file,p-message,message);
1328 if (count != (MagickOffsetType) (p-message))
1329 return(MagickFalse);
1330 count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status);
1331 if (count != (MagickOffsetType) sizeof(status))
1332 return(MagickFalse);
1337 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1341 + 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 %
1345 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1347 % WriteDistributePixelCacheMetacontents() writes image metacontent to the
1348 % specified region of the distributed pixel cache.
1350 % The format of the WriteDistributePixelCacheMetacontents method is:
1352 % MagickOffsetType WriteDistributePixelCacheMetacontents(
1353 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1354 % const MagickSizeType length,const unsigned char *metacontent)
1356 % A description of each parameter follows:
1358 % o server_info: the distributed cache info.
1360 % o image: the image.
1362 % o region: write the metacontent to this region of the image.
1364 % o length: the length in bytes of the metacontent.
1366 % o metacontent: write these metacontent to the pixel cache.
1369 MagickPrivate MagickOffsetType WriteDistributePixelCacheMetacontent(
1370 DistributeCacheInfo *server_info,const RectangleInfo *region,
1371 const MagickSizeType length,const unsigned char *metacontent)
1376 register unsigned char
1380 message[MaxTextExtent];
1383 Write distributed pixel cache metacontent.
1385 assert(server_info != (DistributeCacheInfo *) NULL);
1386 assert(server_info->signature == MagickSignature);
1387 assert(region != (RectangleInfo *) NULL);
1388 assert(metacontent != (unsigned char *) NULL);
1389 if (length > (MagickSizeType) SSIZE_MAX)
1393 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1394 p+=sizeof(server_info->session_key);
1395 (void) memcpy(p,®ion->width,sizeof(region->width));
1396 p+=sizeof(region->width);
1397 (void) memcpy(p,®ion->height,sizeof(region->height));
1398 p+=sizeof(region->height);
1399 (void) memcpy(p,®ion->x,sizeof(region->x));
1400 p+=sizeof(region->x);
1401 (void) memcpy(p,®ion->y,sizeof(region->y));
1402 p+=sizeof(region->y);
1403 (void) memcpy(p,&length,sizeof(length));
1405 count=dpc_send(server_info->file,p-message,message);
1406 if (count != (MagickOffsetType) (p-message))
1408 return(dpc_send(server_info->file,length,metacontent));
1412 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1416 + 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 %
1420 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1422 % WriteDistributePixelCachePixels() writes image pixels to the specified
1423 % region of the distributed pixel cache.
1425 % The format of the WriteDistributePixelCachePixels method is:
1427 % MagickBooleanType WriteDistributePixelCachePixels(
1428 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1429 % const MagickSizeType length,const unsigned char *restrict pixels)
1431 % A description of each parameter follows:
1433 % o server_info: the distributed cache info.
1435 % o image: the image.
1437 % o region: write the pixels to this region of the image.
1439 % o length: the length in bytes of the pixels.
1441 % o pixels: write these pixels to the pixel cache.
1444 MagickPrivate MagickOffsetType WriteDistributePixelCachePixels(
1445 DistributeCacheInfo *server_info,const RectangleInfo *region,
1446 const MagickSizeType length,const unsigned char *restrict pixels)
1451 register unsigned char
1455 message[MaxTextExtent];
1458 Write distributed pixel cache pixels.
1460 assert(server_info != (DistributeCacheInfo *) NULL);
1461 assert(server_info->signature == MagickSignature);
1462 assert(region != (RectangleInfo *) NULL);
1463 assert(pixels != (const unsigned char *) NULL);
1464 if (length > (MagickSizeType) SSIZE_MAX)
1468 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1469 p+=sizeof(server_info->session_key);
1470 (void) memcpy(p,®ion->width,sizeof(region->width));
1471 p+=sizeof(region->width);
1472 (void) memcpy(p,®ion->height,sizeof(region->height));
1473 p+=sizeof(region->height);
1474 (void) memcpy(p,®ion->x,sizeof(region->x));
1475 p+=sizeof(region->x);
1476 (void) memcpy(p,®ion->y,sizeof(region->y));
1477 p+=sizeof(region->y);
1478 (void) memcpy(p,&length,sizeof(length));
1480 count=dpc_send(server_info->file,p-message,message);
1481 if (count != (MagickOffsetType) (p-message))
1483 return(dpc_send(server_info->file,length,pixels));