]> granicus.if.org Git - imagemagick/blob - MagickCore/distribute-cache.c
(no commit message)
[imagemagick] / MagickCore / distribute-cache.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
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   %
10 %                                                                             %
11 %                      CCCC   AAA    CCCC  H   H  EEEEE                       %
12 %                     C      A   A  C      H   H  E                           %
13 %                     C      AAAAA  C      HHHHH  EEE                         %
14 %                     C      A   A  C      H   H  E                           %
15 %                      CCCC  A   A   CCCC  H   H  EEEEE                       %
16 %                                                                             %
17 %                                                                             %
18 %                 MagickCore Distributed Pixel Cache Methods                  %
19 %                                                                             %
20 %                              Software Design                                %
21 %                                John Cristy                                  %
22 %                                January 2013                                 %
23 %                                                                             %
24 %                                                                             %
25 %  Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization      %
26 %  dedicated to making software imaging solutions freely available.           %
27 %                                                                             %
28 %  You may not use this file except in compliance with the License.  You may  %
29 %  obtain a copy of the License at                                            %
30 %                                                                             %
31 %    http://www.imagemagick.org/script/license.php                            %
32 %                                                                             %
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.                                             %
38 %                                                                             %
39 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
40 %
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.
48 %
49 */
50 \f
51 /*
52   Include declarations.
53 */
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/locale_.h"
64 #include "MagickCore/memory_.h"
65 #include "MagickCore/policy.h"
66 #include "MagickCore/random_.h"
67 #include "MagickCore/registry.h"
68 #include "MagickCore/string_.h"
69 #include "MagickCore/string-private.h"
70 #if defined(MAGICKCORE_HAVE_SOCKET)
71 #include <netinet/in.h>
72 #include <netdb.h>
73 #include <sys/socket.h>
74 #include <arpa/inet.h>
75 #endif
76 \f
77 /*
78   Define declarations.
79 */
80 #define DPCHostname  "127.0.0.1"
81 #define DPCPort  6668
82 #define DPCSessionKeyLength  8
83 \f
84 /*
85 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
86 %                                                                             %
87 %                                                                             %
88 %                                                                             %
89 %   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                       %
90 %                                                                             %
91 %                                                                             %
92 %                                                                             %
93 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
94 %
95 %  AcquireDistributeCacheInfo() allocates the DistributeCacheInfo structure.
96 %
97 %  The format of the AcquireDistributeCacheInfo method is:
98 %
99 %      DistributeCacheInfo *AcquireDistributeCacheInfo(ExceptionInfo *exception)
100 %
101 %  A description of each parameter follows:
102 %
103 %    o exception: return any errors or warnings in this structure.
104 %
105 */
106
107 static MagickSizeType CRC64(const unsigned char *message,const size_t length)
108 {
109   MagickSizeType
110     crc;
111
112   register ssize_t
113     i;
114
115   static MagickBooleanType
116     crc_initial = MagickFalse;
117
118   static MagickSizeType
119     crc_xor[256];
120
121   if (crc_initial == MagickFalse)
122     {
123       MagickSizeType
124         alpha;
125
126       for (i=0; i < 256; i++)
127       {
128         register ssize_t
129           j;
130
131         alpha=(MagickSizeType) i;
132         for (j=0; j < 8; j++)
133         {
134           if ((alpha & 0x01) == 0)
135             alpha>>=1;
136           else
137             alpha=(MagickSizeType) ((alpha >> 1) ^
138               MagickULLConstant(0xd800000000000000));
139         }
140         crc_xor[i]=alpha;
141       }
142       crc_initial=MagickTrue;
143     }
144   crc=0;
145   for (i=0; i < (ssize_t) length; i++)
146     crc=crc_xor[(crc ^ message[i]) & 0xff] ^ (crc >> 8);
147   return(crc);
148 }
149
150 static int ConnectPixelCacheServer(const char *hostname,const int port,
151   MagickSizeType *session_key,ExceptionInfo *exception)
152 {
153 #if defined(MAGICKCORE_HAVE_SOCKET)
154   char
155     secret[MaxTextExtent];
156
157   const char
158     *shared_secret;
159
160   int
161     client_socket,
162     status;
163
164   ssize_t
165     count;
166
167   struct hostent
168     *host;
169
170   struct sockaddr_in
171     address;
172
173   unsigned char
174     session[MaxTextExtent];
175
176   /*
177     Connect to distributed pixel cache and get session key.
178   */
179   *session_key=0;
180   shared_secret=GetPolicyValue("shared-secret");
181   if (shared_secret == (const char *) NULL)
182     {
183       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
184         "DistributedPixelCache","'%s'","shared secret expected");
185       return(-1);
186     }
187   (void) CopyMagickString((char *) session,shared_secret,MaxTextExtent-
188     DPCSessionKeyLength);
189   host=gethostbyname(hostname);
190   client_socket=socket(AF_INET,SOCK_STREAM,0);
191   if (client_socket == -1)
192     {
193       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
194         "DistributedPixelCache","'%s'",hostname);
195       return(-1);
196     }
197   (void) ResetMagickMemory(&address,0,sizeof(address));
198   address.sin_family=AF_INET;
199   address.sin_port=htons((uint16_t) port);
200   address.sin_addr=(*((struct in_addr *) host->h_addr));
201   status=connect(client_socket,(struct sockaddr *) &address,(socklen_t)
202     sizeof(struct sockaddr));
203   if (status == -1)
204     {
205       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
206         "DistributedPixelCache","'%s'",hostname);
207       return(-1);
208     }
209   count=read(client_socket,secret,MaxTextExtent);
210   if (count != -1)
211     {
212       (void) memcpy(session+strlen(shared_secret),secret,(size_t) count);
213       *session_key=CRC64(session,strlen(shared_secret)+count);
214     }
215   if (*session_key == 0)
216     {
217       close(client_socket);
218       client_socket=(-1);
219     }
220   return(client_socket);
221 #else
222   (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
223     "DelegateLibrarySupportNotBuiltIn","distributed pixel cache");
224   return(MagickFalse);
225 #endif
226 }
227
228 static char *GetHostname(int *port,ExceptionInfo *exception)
229 {
230   char
231     *host,
232     *hosts,
233     **hostlist;
234
235   int
236     argc;
237
238   register ssize_t
239     i;
240
241   static size_t
242     id = 0;
243
244   /*
245     Parse host list (e.g. 192.168.100.1:6668,192.168.100.2:6668).
246   */
247   hosts=(char *) GetImageRegistry(StringRegistryType,"cache:hosts",
248     exception);
249   if (hosts == (char *) NULL)
250     {
251       *port=DPCPort;
252       return(AcquireString(DPCHostname));
253     }
254   (void) SubstituteString(&hosts,","," ");
255   hostlist=StringToArgv(hosts,&argc);
256   hosts=DestroyString(hosts);
257   if (hostlist == (char **) NULL)
258     {
259       *port=DPCPort;
260       return(AcquireString(DPCHostname));
261     }
262   hosts=AcquireString(hostlist[(id++ % (argc-1))+1]);
263   for (i=0; i < (ssize_t) argc; i++)
264     hostlist[i]=DestroyString(hostlist[i]);
265   hostlist=(char **) RelinquishMagickMemory(hostlist);
266   (void) SubstituteString(&hosts,":"," ");
267   hostlist=StringToArgv(hosts,&argc);
268   if (hostlist == (char **) NULL)
269     {
270       *port=DPCPort;
271       return(AcquireString(DPCHostname));
272     }
273   host=AcquireString(hostlist[1]);
274   if (hostlist[2] == (char *) NULL)
275     *port=DPCPort;
276   else
277     *port=StringToLong(hostlist[2]);
278   for (i=0; i < (ssize_t) argc; i++)
279     hostlist[i]=DestroyString(hostlist[i]);
280   hostlist=(char **) RelinquishMagickMemory(hostlist);
281   return(host);
282 }
283
284 MagickPrivate DistributeCacheInfo *AcquireDistributeCacheInfo(
285   ExceptionInfo *exception)
286 {
287   char
288     *hostname;
289
290   DistributeCacheInfo
291     *distribute_cache_info;
292
293   MagickSizeType
294     session_key;
295
296   distribute_cache_info=(DistributeCacheInfo *) AcquireMagickMemory(
297     sizeof(*distribute_cache_info));
298   if (distribute_cache_info == (DistributeCacheInfo *) NULL)
299     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
300   (void) ResetMagickMemory(distribute_cache_info,0,
301     sizeof(*distribute_cache_info));
302   distribute_cache_info->signature=MagickSignature;
303   /*
304     Contact pixel cache server.
305   */
306   distribute_cache_info->port=0;
307   hostname=GetHostname(&distribute_cache_info->port,exception);
308   session_key=0;
309   distribute_cache_info->file=ConnectPixelCacheServer(hostname,
310     distribute_cache_info->port,&session_key,exception);
311   distribute_cache_info->session_key=session_key;
312   (void) CopyMagickString(distribute_cache_info->hostname,hostname,
313     MaxTextExtent);
314   hostname=DestroyString(hostname);
315   if (distribute_cache_info->file == -1)
316     distribute_cache_info=DestroyDistributeCacheInfo(distribute_cache_info);
317   return(distribute_cache_info);
318 }
319 \f
320 /*
321 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
322 %                                                                             %
323 %                                                                             %
324 %                                                                             %
325 %   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                       %
326 %                                                                             %
327 %                                                                             %
328 %                                                                             %
329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
330 %
331 %  DestroyDistributeCacheInfo() deallocates memory associated with an
332 %  DistributeCacheInfo structure.
333 %
334 %  The format of the DestroyDistributeCacheInfo method is:
335 %
336 %      DistributeCacheInfo *DestroyDistributeCacheInfo(
337 %        DistributeCacheInfo *distribute_cache_info)
338 %
339 %  A description of each parameter follows:
340 %
341 %    o distribute_cache_info: the distributed cache info.
342 %
343 */
344 MagickPrivate DistributeCacheInfo *DestroyDistributeCacheInfo(
345   DistributeCacheInfo *distribute_cache_info)
346 {
347   assert(distribute_cache_info != (DistributeCacheInfo *) NULL);
348   assert(distribute_cache_info->signature == MagickSignature);
349   distribute_cache_info->signature=(~MagickSignature);
350   distribute_cache_info=(DistributeCacheInfo *) RelinquishMagickMemory(
351     distribute_cache_info);
352   return(distribute_cache_info);
353 }
354 \f
355 /*
356 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
357 %                                                                             %
358 %                                                                             %
359 %                                                                             %
360 +   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                       %
361 %                                                                             %
362 %                                                                             %
363 %                                                                             %
364 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
365 %
366 %  DistributePixelCacheServer() waits on the specified port for commands to
367 %  create, read, update, or destroy a pixel cache.
368 %
369 %  The format of the DistributePixelCacheServer() method is:
370 %
371 %      void DistributePixelCacheServer(const size_t port)
372 %
373 %  A description of each parameter follows:
374 %
375 %    o port: connect the distributed pixel cache at this port.
376 %
377 %    o exception: return any errors or warnings in this structure.
378 %
379 */
380
381 static MagickBooleanType CreateDistributeCache(int file,
382   const MagickSizeType session_key)
383 {
384   char
385     key[MaxTextExtent];
386
387   ExceptionInfo
388     *exception;
389
390   Image
391     *image;
392
393   MagickBooleanType
394     status;
395
396   ssize_t
397     count;
398
399   exception=AcquireExceptionInfo();
400   image=AcquireImage((ImageInfo *) NULL,exception);
401   count=read(file,&image->columns,sizeof(image->columns));
402   if (count != (ssize_t) sizeof(image->columns))
403     return(MagickFalse);
404   count=read(file,&image->rows,sizeof(image->rows));
405   if (count != (ssize_t) sizeof(image->rows))
406     return(MagickFalse);
407   count=read(file,&image->number_channels,sizeof(image->number_channels));
408   if (count != (ssize_t) sizeof(image->number_channels))
409     return(MagickFalse);
410   (void) FormatLocaleString(key,MaxTextExtent,"%.20g",(double) session_key);
411   status=SetImageRegistry(ImageRegistryType,key,image,exception);
412   exception=DestroyExceptionInfo(exception);
413   image=DestroyImage(image);
414   return(status);
415 }
416
417 static MagickBooleanType DestroyDistributeCache(int file,
418   const MagickSizeType session_key)
419 {
420   char
421     key[MaxTextExtent];
422
423   (void) FormatLocaleString(key,MaxTextExtent,"%.20g",(double) session_key);
424   return(DeleteImageRegistry(key));
425 }
426
427 static MagickBooleanType ReadDistributeCache(int file,
428   const MagickSizeType session_key)
429 {
430   char
431     key[MaxTextExtent];
432
433   CacheInfo
434     *cache_info;
435
436   ExceptionInfo
437     *exception;
438
439   Image
440     *image;
441
442   RectangleInfo
443     region;
444
445   register const Quantum
446     *p;
447
448   size_t
449     length;
450
451   ssize_t
452     count;
453
454   exception=AcquireExceptionInfo();
455   (void) FormatLocaleString(key,MaxTextExtent,"%.20g",(double) session_key);
456   image=(Image *) GetImageRegistry(ImageRegistryType,key,exception);
457   exception=DestroyExceptionInfo(exception);
458   if (image == (Image *) NULL)
459     return(MagickFalse);
460   cache_info=(CacheInfo *) image->cache;
461   count=read(file,&region.width,sizeof(region.width));
462   if (count != (ssize_t) sizeof(region.width))
463     return(MagickFalse);
464   count=read(file,&region.height,sizeof(region.height));
465   if (count != (ssize_t) sizeof(region.height))
466     return(MagickFalse);
467   count=read(file,&region.x,sizeof(region.x));
468   if (count != (ssize_t) sizeof(region.width))
469     return(MagickFalse);
470   count=read(file,&region.y,sizeof(region.y));
471   if (count != (ssize_t) sizeof(region.y))
472     return(MagickFalse);
473   length=(size_t) (region.width*cache_info->number_channels*sizeof(Quantum));
474   exception=AcquireExceptionInfo();
475   p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
476     exception);
477   exception=DestroyExceptionInfo(exception);
478   if (p != (const Quantum *) NULL)
479     return(MagickFalse);
480   count=write(file,p,length);
481   if (count != (ssize_t) length)
482     return(MagickFalse);
483   return(MagickTrue);
484 }
485
486 static MagickBooleanType WriteDistributeCache(int file,
487   const MagickSizeType session_key)
488 {
489   char
490     key[MaxTextExtent];
491
492   CacheInfo
493     *cache_info;
494
495   ExceptionInfo
496     *exception;
497
498   Image
499     *image;
500
501   MagickBooleanType
502     status;
503
504   RectangleInfo
505     region;
506
507   register Quantum
508     *p;
509
510   size_t
511     length;
512
513   ssize_t
514     count;
515
516   exception=AcquireExceptionInfo();
517   (void) FormatLocaleString(key,MaxTextExtent,"%.20g",(double) session_key);
518   image=(Image *) GetImageRegistry(ImageRegistryType,key,exception);
519   exception=DestroyExceptionInfo(exception);
520   if (image == (Image *) NULL)
521     return(MagickFalse);
522   cache_info=(CacheInfo *) image->cache;
523   count=read(file,&region.width,sizeof(region.width));
524   if (count != (ssize_t) sizeof(region.width))
525     return(MagickFalse);
526   count=read(file,&region.height,sizeof(region.height));
527   if (count != (ssize_t) sizeof(region.height))
528     return(MagickFalse);
529   count=read(file,&region.x,sizeof(region.x));
530   if (count != (ssize_t) sizeof(region.width))
531     return(MagickFalse);
532   count=read(file,&region.y,sizeof(region.y));
533   if (count != (ssize_t) sizeof(region.y))
534     return(MagickFalse);
535   length=(size_t) (region.width*cache_info->number_channels*sizeof(Quantum));
536   p=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
537     exception);
538   exception=DestroyExceptionInfo(exception);
539   if (p != (Quantum *) NULL)
540     return(MagickFalse);
541   count=read(file,p,length);
542   if (count != (ssize_t) length)
543     return(MagickFalse);
544   status=SyncAuthenticPixels(image,exception);
545   return(status);
546 }
547
548 static void *DistributePixelCacheClient(void *socket)
549 {
550   const char
551     *shared_secret;
552
553   int
554     client_socket,
555     status;
556
557   MagickSizeType
558     key,
559     session_key;
560
561   RandomInfo
562     *random_info;
563
564   ssize_t
565     count;
566
567   StringInfo
568     *secret;
569
570   unsigned char
571     command,
572     session[MaxTextExtent];
573
574   /*
575     Generate session key.
576   */
577   shared_secret=GetPolicyValue("shared-secret");
578   if (shared_secret == (const char *) NULL)
579     ThrowFatalException(CacheFatalError,"shared secret expected");
580   (void) CopyMagickString((char *) session,shared_secret,MaxTextExtent-
581     DPCSessionKeyLength);
582   random_info=AcquireRandomInfo();
583   secret=GetRandomKey(random_info,DPCSessionKeyLength);
584   (void) memcpy(session+strlen(shared_secret),GetStringInfoDatum(secret),
585     DPCSessionKeyLength);
586   session_key=CRC64(session,strlen(shared_secret)+DPCSessionKeyLength);
587   random_info=DestroyRandomInfo(random_info);
588   client_socket=(*(int *) socket);
589   count=write(client_socket,GetStringInfoDatum(secret),DPCSessionKeyLength);
590   secret=DestroyStringInfo(secret);
591   for ( ; ; )
592   {
593     count=read(client_socket,&command,1);
594     if (count <= 0)
595       break;
596     count=read(client_socket,&key,sizeof(key));
597     if ((count != (ssize_t) sizeof(key)) && (key != session_key))
598       break;
599     status=MagickFalse;
600     switch (command)
601     {
602       case 'c':
603       {
604         status=CreateDistributeCache(client_socket,session_key);
605         break;
606       }
607       case 'd':
608       {
609         status=DestroyDistributeCache(client_socket,session_key);
610         break;
611       }
612       case 'r':
613       {
614         status=ReadDistributeCache(client_socket,session_key);
615         break;
616       }
617       case 'w':
618       {
619         status=WriteDistributeCache(client_socket,session_key);
620         break;
621       }
622       default:
623         break;
624     }
625     count=write(client_socket,&status,sizeof(status));
626     if (count != (ssize_t) sizeof(status))
627       break;
628   }
629   return((void *) NULL);
630 }
631
632 MagickExport void DistributePixelCacheServer(const size_t port,
633   ExceptionInfo *exception)
634 {
635 #if defined(MAGICKCORE_HAVE_SOCKET) && defined(MAGICKCORE_THREAD_SUPPORT)
636   int
637     server_socket,
638     status;
639
640   pthread_attr_t
641     attributes;
642
643   pthread_t
644     threads;
645
646   struct sockaddr_in
647     address;
648
649   /*
650     Launch distributed pixel cache server.
651   */
652   server_socket=socket(AF_INET,SOCK_STREAM,0);
653   address.sin_family=AF_INET;
654   address.sin_port=htons(port);
655   address.sin_addr.s_addr=htonl(INADDR_ANY);
656   status=bind(server_socket,(struct sockaddr *) &address,(socklen_t)
657     sizeof(address));
658   if (status != 0)
659     ThrowFatalException(CacheFatalError,"UnableToBind");
660   status=listen(server_socket,32);
661   if (status != 0)
662     ThrowFatalException(CacheFatalError,"UnableToListen");
663   pthread_attr_init(&attributes);
664   for ( ; ; )
665   {
666     int
667       client_socket;
668
669     socklen_t
670       length;
671
672     length=(socklen_t) sizeof(address);
673     client_socket=accept(server_socket,(struct sockaddr *) &address,&length);
674     if (client_socket == -1)
675       ThrowFatalException(CacheFatalError,"UnableToEstablishConnection");
676     status=pthread_create(&threads,&attributes,DistributePixelCacheClient,
677       (void *) &client_socket);
678     if (status == -1)
679       ThrowFatalException(CacheFatalError,"UnableToCreateClientThread");
680   }
681   (void) close(server_socket);
682 #else
683   ThrowFatalException(MissingDelegateError,"distributed pixel cache");
684 #endif
685 }
686 \f
687 /*
688 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
689 %                                                                             %
690 %                                                                             %
691 %                                                                             %
692 %   O p e n D i s t r i b u t e P i x e l C a c h e                           %
693 %                                                                             %
694 %                                                                             %
695 %                                                                             %
696 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
697 %
698 %  OpenDistributePixelCache() opens a pixel cache on a remote server.
699 %
700 %  The format of the OpenDistributePixelCache method is:
701 %
702 %      MagickBooleanType *OpenDistributePixelCache(
703 %        DistributeCacheInfo *distribute_cache_info,Image *image)
704 %
705 %  A description of each parameter follows:
706 %
707 %    o distribute_cache_info: the distributed cache info.
708 %
709 %    o image: the image.
710 %
711 */
712 MagickPrivate MagickBooleanType OpenDistributePixelCache(
713   DistributeCacheInfo *distribute_cache_info,Image *image)
714 {
715   int
716     file;
717
718   MagickBooleanType
719     status;
720
721   MagickSizeType
722     session_key;
723
724   ssize_t
725     count;
726
727   assert(distribute_cache_info != (DistributeCacheInfo *) NULL);
728   assert(distribute_cache_info->signature == MagickSignature);
729   assert(image != (Image *) NULL);
730   assert(image->signature == MagickSignature);
731   file=distribute_cache_info->file;
732   session_key=distribute_cache_info->session_key;
733   count=write(file,"c",1);
734   if (count != 1)
735     return(MagickFalse);
736   count=write(file,&session_key,sizeof(session_key));
737   if (count != (ssize_t) sizeof(session_key))
738     return(MagickFalse);
739   count=write(file,&image->columns,sizeof(image->columns));
740   if (count != (ssize_t) sizeof(image->columns))
741     return(MagickFalse);
742   count=write(file,&image->rows,sizeof(image->rows));
743   if (count != (ssize_t) sizeof(image->rows))
744     return(MagickFalse);
745   count=write(file,&image->number_channels,sizeof(image->number_channels));
746   if (count != (ssize_t) sizeof(image->number_channels))
747     return(MagickFalse);
748   count=read(file,&status,sizeof(status));
749   if (count != (ssize_t) sizeof(status))
750     return(MagickFalse);
751   return(MagickTrue);
752 }
753 \f
754 /*
755 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
756 %                                                                             %
757 %                                                                             %
758 %                                                                             %
759 %   R e a d D i s t r i b u t e P i x e l C a c h e                           %
760 %                                                                             %
761 %                                                                             %
762 %                                                                             %
763 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
764 %
765 %  ReadDistributePixelCache() reads pixels from the specified region of the
766 %  distributed pixel cache.
767 %
768 %  The format of the ReadDistributePixelCache method is:
769 %
770 %      MagickBooleanType *ReadDistributePixelCache(
771 %        DistributeCacheInfo *distribute_cache_info,const RectangleInfo *region,
772 %        Quantum *pixels)
773 %
774 %  A description of each parameter follows:
775 %
776 %    o distribute_cache_info: the distributed cache info.
777 %
778 %    o image: the image.
779 %
780 %    o region: read the pixels from this region of the image.
781 %
782 %    o pixels: read these pixels from the pixel cache.
783 %
784 */
785 MagickPrivate MagickBooleanType ReadDistributePixelCache(
786   DistributeCacheInfo *distribute_cache_info,const RectangleInfo *region,
787   Quantum *pixels)
788 {
789   CacheInfo
790     *cache_info;
791
792   char
793     key[MaxTextExtent];
794
795   ExceptionInfo
796     *exception;
797
798   int
799     file;
800
801   Image
802     *image;
803
804   MagickBooleanType
805     status;
806
807   MagickSizeType
808     session_key;
809
810   size_t
811     length;
812
813   ssize_t
814     count;
815
816   assert(distribute_cache_info != (DistributeCacheInfo *) NULL);
817   assert(distribute_cache_info->signature == MagickSignature);
818   assert(region != (RectangleInfo *) NULL);
819   assert(pixels != (Quantum *) NULL);
820   exception=AcquireExceptionInfo();
821   (void) FormatLocaleString(key,MaxTextExtent,"%.20g",(double) session_key);
822   image=(Image *) GetImageRegistry(ImageRegistryType,key,exception);
823   exception=DestroyExceptionInfo(exception);
824   if (image == (Image *) NULL)
825     return(MagickFalse);
826   cache_info=(CacheInfo *) image->cache;
827   file=distribute_cache_info->file;
828   session_key=distribute_cache_info->session_key;
829   count=write(file,"r",1);
830   if (count != 1)
831     return(MagickFalse);
832   count=write(file,&session_key,sizeof(session_key));
833   if (count != (ssize_t) sizeof(session_key))
834     return(MagickFalse);
835   count=write(file,&region->width,sizeof(region->width));
836   if (count != (ssize_t) sizeof(region->width))
837     return(MagickFalse);
838   count=write(file,&region->height,sizeof(region->height));
839   if (count != (ssize_t) sizeof(region->height))
840     return(MagickFalse);
841   count=write(file,&region->x,sizeof(region->x));
842   if (count != (ssize_t) sizeof(region->x))
843     return(MagickFalse);
844   count=write(file,&region->y,sizeof(region->x));
845   if (count != (ssize_t) sizeof(region->y))
846     return(MagickFalse);
847   length=(size_t) (region->width*cache_info->number_channels*sizeof(Quantum));
848   count=read(file,(unsigned char *) pixels,length);
849   if (count != (ssize_t) length)
850     return(MagickFalse);
851   count=read(file,&status,sizeof(status));
852   if (count != (ssize_t) sizeof(status))
853     return(MagickFalse);
854   return(MagickTrue);
855 }
856 \f
857 /*
858 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
859 %                                                                             %
860 %                                                                             %
861 %                                                                             %
862 %   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               %
863 %                                                                             %
864 %                                                                             %
865 %                                                                             %
866 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
867 %
868 %  RelinquishDistributePixelCache() frees resources acquired with
869 %  OpenDistributePixelCache().
870 %
871 %  The format of the RelinquishDistributePixelCache method is:
872 %
873 %      void RelinquishDistributePixelCache(
874 %        DistributeCacheInfo *distribute_cache_info)
875 %
876 %  A description of each parameter follows:
877 %
878 %    o distribute_cache_info: the distributed cache info.
879 %
880 */
881 MagickPrivate void RelinquishDistributePixelCache(
882   DistributeCacheInfo *distribute_cache_info)
883 {
884   int
885     file;
886
887   MagickSizeType
888     session_key;
889
890   assert(distribute_cache_info != (DistributeCacheInfo *) NULL);
891   assert(distribute_cache_info->signature == MagickSignature);
892   file=distribute_cache_info->file;
893   session_key=distribute_cache_info->session_key;
894   (void) write(file,"c",1);
895   (void) write(file,&session_key,sizeof(session_key));
896 }
897 \f
898 /*
899 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
900 %                                                                             %
901 %                                                                             %
902 %                                                                             %
903 %   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                         %
904 %                                                                             %
905 %                                                                             %
906 %                                                                             %
907 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
908 %
909 %  WriteDistributePixelCache() writes image pixels to the specified region of
910 %  the distributed pixel cache.
911
912 %
913 %  The format of the WriteDistributePixelCache method is:
914 %
915 %      MagickBooleanType *WriteDistributePixelCache(
916 %        DistributeCacheInfo *distribute_cache_info,const RectangleInfo *region,
917 %        const Quantum *pixels)
918 %
919 %  A description of each parameter follows:
920 %
921 %    o distribute_cache_info: the distributed cache info.
922 %
923 %    o image: the image.
924 %
925 %    o region: write the pixels to this region of the image.
926 %
927 %    o pixels: write these pixels to the pixel cache.
928 %
929 */
930 MagickPrivate MagickBooleanType WriteDistributePixelCache(
931   DistributeCacheInfo *distribute_cache_info,const RectangleInfo *region,
932   const Quantum *pixels)
933 {
934   CacheInfo
935     *cache_info;
936
937   char
938     key[MaxTextExtent];
939
940   ExceptionInfo
941     *exception;
942
943   int
944     file;
945
946   Image
947     *image;
948
949   MagickBooleanType
950     status;
951
952   MagickSizeType
953     session_key;
954
955   size_t
956     length;
957
958   ssize_t
959     count;
960
961   assert(distribute_cache_info != (DistributeCacheInfo *) NULL);
962   assert(distribute_cache_info->signature == MagickSignature);
963   assert(region != (RectangleInfo *) NULL);
964   assert(pixels != (Quantum *) NULL);
965   exception=AcquireExceptionInfo();
966   (void) FormatLocaleString(key,MaxTextExtent,"%.20g",(double) session_key);
967   image=(Image *) GetImageRegistry(ImageRegistryType,key,exception);
968   exception=DestroyExceptionInfo(exception);
969   if (image == (Image *) NULL)
970     return(MagickFalse);
971   cache_info=(CacheInfo *) image->cache;
972   file=distribute_cache_info->file;
973   session_key=distribute_cache_info->session_key;
974   count=write(file,"u",1);
975   if (count != 1)
976     return(MagickFalse);
977   count=write(file,&session_key,sizeof(session_key));
978   if (count != (ssize_t) sizeof(session_key))
979     return(MagickFalse);
980   count=write(file,&region->width,sizeof(region->width));
981   if (count != (ssize_t) sizeof(region->width))
982     return(MagickFalse);
983   count=write(file,&region->height,sizeof(region->height));
984   if (count != (ssize_t) sizeof(region->height))
985     return(MagickFalse);
986   count=write(file,&region->x,sizeof(region->x));
987   if (count != (ssize_t) sizeof(region->x))
988     return(MagickFalse);
989   count=write(file,&region->y,sizeof(region->x));
990   if (count != (ssize_t) sizeof(region->y))
991     return(MagickFalse);
992   length=(size_t) (region->width*cache_info->number_channels*sizeof(Quantum));
993   count=write(file,(unsigned char *) pixels,length);
994   if (count != (ssize_t) length)
995     return(MagickFalse);
996   count=read(file,&status,sizeof(status));
997   if (count != (ssize_t) sizeof(status))
998     return(MagickFalse);
999   return(MagickTrue);
1000 }