All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
as_policy.h
Go to the documentation of this file.
1 /*
2  * Copyright 2008-2015 Aerospike, Inc.
3  *
4  * Portions may be licensed to Aerospike, Inc. under one or more contributor
5  * license agreements.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
8  * use this file except in compliance with the License. You may obtain a copy of
9  * the License at http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14  * License for the specific language governing permissions and limitations under
15  * the License.
16  */
17 #pragma once
18 
19 /**
20  * @defgroup client_policies Client Policies
21  *
22  * Policies define the behavior of database operations.
23  *
24  * Policies fall into two groups: policy values and operation policies.
25  * A policy value is a single value which defines how the client behaves. An
26  * operation policy is a group of policy values which affect an operation.
27  *
28  * ## Policy Values
29  *
30  * The following are the policy values. For details, please see the documentation
31  * for each policy value
32  *
33  * - as_policy_key
34  * - as_policy_gen
35  * - as_policy_retry
36  * - as_policy_exists
37  * - as_policy_replica
38  * - as_policy_consistency_level
39  * - as_policy_commit_level
40  *
41  * ## Operation Policies
42  *
43  * The following are the operation policies. Operation policies are groups of
44  * policy values for a type of operation.
45  *
46  * - as_policy_batch
47  * - as_policy_info
48  * - as_policy_operate
49  * - as_policy_read
50  * - as_policy_remove
51  * - as_policy_query
52  * - as_policy_scan
53  * - as_policy_write
54  */
55 
56 #include <stdbool.h>
57 #include <stdint.h>
58 
59 #ifdef __cplusplus
60 extern "C" {
61 #endif
62 
63 /******************************************************************************
64  * MACROS
65  *****************************************************************************/
66 
67 /**
68  * Default timeout value
69  *
70  * @ingroup client_policies
71  */
72 #define AS_POLICY_TIMEOUT_DEFAULT 1000
73 
74 /**
75  * Default as_policy_retry value
76  *
77  * @ingroup client_policies
78  */
79 #define AS_POLICY_RETRY_DEFAULT AS_POLICY_RETRY_ONCE
80 
81 /**
82  * Default as_policy_gen value
83  *
84  * @ingroup client_policies
85  */
86 #define AS_POLICY_GEN_DEFAULT AS_POLICY_GEN_IGNORE
87 
88 /**
89  * Default as_policy_key value
90  *
91  * @ingroup client_policies
92  */
93 #define AS_POLICY_KEY_DEFAULT AS_POLICY_KEY_DIGEST
94 
95 /**
96  * Default as_policy_exists value
97  *
98  * @ingroup client_policies
99  */
100 #define AS_POLICY_EXISTS_DEFAULT AS_POLICY_EXISTS_IGNORE
101 
102 /**
103  * Default as_policy_replica value
104  *
105  * @ingroup client_policies
106  */
107 #define AS_POLICY_REPLICA_DEFAULT AS_POLICY_REPLICA_MASTER
108 
109 /**
110  * Default as_policy_consistency_level value for read
111  *
112  * @ingroup client_policies
113  */
114 #define AS_POLICY_CONSISTENCY_LEVEL_DEFAULT AS_POLICY_CONSISTENCY_LEVEL_ONE
115 
116 /**
117  * Default as_policy_commit_level value for write
118  *
119  * @ingroup client_policies
120  */
121 #define AS_POLICY_COMMIT_LEVEL_DEFAULT AS_POLICY_COMMIT_LEVEL_ALL
122 
123 /******************************************************************************
124  * TYPES
125  *****************************************************************************/
126 
127 /**
128  * Retry Policy
129  *
130  * Specifies the behavior of failed operations.
131  *
132  * @ingroup client_policies
133  */
134 typedef enum as_policy_retry_e {
135 
136  /**
137  * Only attempt an operation once.
138  */
140 
141  /**
142  * If an operation fails, attempt the operation
143  * one more time.
144  */
146 
148 
149 /**
150  * Generation Policy
151  *
152  * Specifies the behavior of record modifications with regard to the
153  * generation value.
154  *
155  * @ingroup client_policies
156  */
157 typedef enum as_policy_gen_e {
158 
159  /**
160  * Write a record, regardless of generation.
161  */
163 
164  /**
165  * Write a record, ONLY if generations are equal
166  */
168 
169  /**
170  * Write a record, ONLY if local generation is
171  * greater-than remote generation
172  */
174 
175 } as_policy_gen;
176 
177 /**
178  * Key Policy
179  *
180  * Specifies the behavior for whether keys or digests
181  * should be sent to the cluster.
182  *
183  * @ingroup client_policies
184  */
185 typedef enum as_policy_key_e {
186 
187  /**
188  * Send the digest value of the key.
189  *
190  * This is the recommended mode of operation. This calculates the digest
191  * and send the digest to the server. The digest is only calculated on
192  * the client, and not on the server.
193  */
195 
196  /**
197  * Send the key, in addition to the digest value.
198  *
199  * If you want keys to be returned when scanning or querying, the keys must
200  * be stored on the server. This policy causes a write operation to store
201  * the key. Once a key is stored, the server will keep it - there is no
202  * need to use this policy on subsequent updates of the record.
203  *
204  * If this policy is used on read or delete operations, or on subsequent
205  * updates of a record with a stored key, the key sent will be compared
206  * with the key stored on the server. A mismatch will cause
207  * AEROSPIKE_ERR_RECORD_KEY_MISMATCH to be returned.
208  */
210 
211 } as_policy_key;
212 
213 /**
214  * Existence Policy
215  *
216  * Specifies the behavior for writing the record
217  * depending whether or not it exists.
218  *
219  * @ingroup client_policies
220  */
221 typedef enum as_policy_exists_e {
222 
223  /**
224  * Write the record, regardless of existence. (i.e. create or update.)
225  */
227 
228  /**
229  * Create a record, ONLY if it doesn't exist.
230  */
232 
233  /**
234  * Update a record, ONLY if it exists.
235  */
237 
238  /**
239  * Completely replace a record, ONLY if it exists.
240  */
242 
243  /**
244  * Completely replace a record if it exists, otherwise create it.
245  */
247 
249 
250 /**
251  * Replica Policy
252  *
253  * Specifies which partition replica to read from.
254  *
255  * @ingroup client_policies
256  */
257 typedef enum as_policy_replica_e {
258 
259  /**
260  * Read from the partition master replica node.
261  */
263 
264  /**
265  * Read from an unspecified replica node.
266  */
268 
270 
271 /**
272  * Consistency Level
273  *
274  * Specifies the number of replicas to be consulted
275  * in a read operation to provide the desired
276  * consistency guarantee.
277  *
278  * @ingroup client_policies
279  */
280 typedef enum as_policy_consistency_level_e {
281 
282  /**
283  * Involve a single replica in the operation.
284  */
286 
287  /**
288  * Involve all replicas in the operation.
289  */
291 
293 
294 /**
295  * Commit Level
296  *
297  * Specifies the number of replicas required to be successfully
298  * committed before returning success in a write operation
299  * to provide the desired consistency guarantee.
300  *
301  * @ingroup client_policies
302  */
303 typedef enum as_policy_commit_level_e {
304 
305  /**
306  * Return succcess only after successfully committing all replicas.
307  */
309 
310  /**
311  * Return succcess after successfully committing the master replica.
312  */
314 
316 
317 /**
318  * Write Policy
319  *
320  * @ingroup client_policies
321  */
322 typedef struct as_policy_write_s {
323 
324  /**
325  * Maximum time in milliseconds to wait for
326  * the operation to complete.
327  */
328  uint32_t timeout;
329 
330  /**
331  * Specifies the behavior for failed operations.
332  */
334 
335  /**
336  * Specifies the behavior for the key.
337  */
339 
340  /**
341  * Specifies the behavior for the generation
342  * value.
343  */
345 
346  /**
347  * Specifies the behavior for the existence
348  * of the record.
349  */
351 
352  /**
353  * Specifies the number of replicas required
354  * to be committed successfully when writing
355  * before returning transaction succeeded.
356  */
358 
360 
361 /**
362  * Read Policy
363  *
364  * @ingroup client_policies
365  */
366 typedef struct as_policy_read_s {
367 
368  /**
369  * Maximum time in milliseconds to wait for
370  * the operation to complete.
371  */
372  uint32_t timeout;
373 
374  /**
375  * Specifies the behavior for the key.
376  */
378 
379  /**
380  * Specifies the replica to be consulted for the read.
381  */
383 
384  /**
385  * Specifies the number of replicas consulted
386  * when reading for the desired consistency guarantee.
387  */
389 
391 
392 /**
393  * Key Apply Policy
394  *
395  * @ingroup client_policies
396  */
397 typedef struct as_policy_apply_s {
398 
399  /**
400  * Maximum time in milliseconds to wait for
401  * the operation to complete.
402  */
403  uint32_t timeout;
404 
405  /**
406  * Specifies the behavior for the key.
407  */
409 
410  /**
411  * Specifies the number of replicas required
412  * to be committed successfully when writing
413  * before returning transaction succeeded.
414  */
416 
417  /**
418  * The time-to-live (expiration) of the record in seconds.
419  * There are two special values that can be set in the record TTL:
420  * (*) ZERO (defined as AS_RECORD_DEFAULT_TTL), which means that the
421  * record will adopt the default TTL value from the namespace.
422  * (*) 0xFFFFFFFF (also, -1 in a signed 32 bit int)
423  * (defined as AS_RECORD_NO_EXPIRE_TTL), which means that the record
424  * will get an internal "void_time" of zero, and thus will never expire.
425  *
426  * Note that the TTL value will be employed ONLY on write/update calls.
427  */
428  uint32_t ttl;
429 
431 
432 /**
433  * Operate Policy
434  *
435  * @ingroup client_policies
436  */
437 typedef struct as_policy_operate_s {
438 
439  /**
440  * Maximum time in milliseconds to wait for
441  * the operation to complete.
442  */
443  uint32_t timeout;
444 
445  /**
446  * Specifies the behavior for failed operations.
447  */
449 
450  /**
451  * Specifies the behavior for the key.
452  */
454 
455  /**
456  * Specifies the behavior for the generation
457  * value.
458  */
460 
461  /**
462  * Specifies the replica to be consulted for the read.
463  */
465 
466  /**
467  * Specifies the number of replicas consulted
468  * when reading for the desired consistency guarantee.
469  */
471 
472  /**
473  * Specifies the number of replicas required
474  * to be committed successfully when writing
475  * before returning transaction succeeded.
476  */
478 
480 
481 /**
482  * Remove Policy
483  *
484  * @ingroup client_policies
485  */
486 typedef struct as_policy_remove_s {
487 
488  /**
489  * Maximum time in milliseconds to wait for
490  * the operation to complete.
491  */
492  uint32_t timeout;
493 
494  /**
495  * The generation of the record.
496  */
497  uint16_t generation;
498 
499  /**
500  * Specifies the behavior of failed operations.
501  */
503 
504  /**
505  * Specifies the behavior for the key.
506  */
508 
509  /**
510  * Specifies the behavior for the generation
511  * value.
512  */
514 
515  /**
516  * Specifies the number of replicas required
517  * to be committed successfully when writing
518  * before returning transaction succeeded.
519  */
521 
523 
524 /**
525  * Query Policy
526  *
527  * @ingroup client_policies
528  */
529 typedef struct as_policy_query_s {
530 
531  /**
532  * Maximum time in milliseconds to wait for
533  * the operation to complete.
534  *
535  * The default (0) means do not timeout.
536  */
537  uint32_t timeout;
538 
540 
541 /**
542  * Scan Policy
543  *
544  * @ingroup client_policies
545  */
546 typedef struct as_policy_scan_s {
547 
548  /**
549  * Maximum time in milliseconds to wait for the operation to complete.
550  *
551  * The default (0) means do not timeout.
552  */
553  uint32_t timeout;
554 
555  /**
556  * Abort the scan if the cluster is not in a
557  * stable state.
558  */
560 
562 
563 /**
564  * Info Policy
565  *
566  * @ingroup client_policies
567  */
568 typedef struct as_policy_info_s {
569 
570  /**
571  * Maximum time in milliseconds to wait for
572  * the operation to complete.
573  */
574  uint32_t timeout;
575 
576  /**
577  * Send request without any further processing.
578  */
580 
581  /**
582  * Ensure the request is within allowable size limits.
583  */
585 
587 
588 /**
589  * Batch Policy
590  *
591  * @ingroup client_policies
592  */
593 typedef struct as_policy_batch_s {
594 
595  /**
596  * Maximum time in milliseconds to wait for
597  * the operation to complete.
598  */
599  uint32_t timeout;
600 
601  /**
602  * Determine if batch commands to each server are run in parallel threads.
603  * <p>
604  * Values:
605  * <ul>
606  * <li>
607  * false: Issue batch commands sequentially. This mode has a performance advantage for small
608  * to medium sized batch sizes because commands can be issued in the main transaction thread.
609  * This is the default.
610  * </li>
611  * <li>
612  * true: Issue batch commands in parallel threads. This mode has a performance
613  * advantage for large batch sizes because each node can process the command immediately.
614  * The downside is extra threads will need to be created (or taken from
615  * a thread pool).
616  * </li>
617  * </ul>
618  */
620 
621  /**
622  * Use old batch direct protocol where batch reads are handled by direct low-level batch server
623  * database routines. The batch direct protocol can be faster when there is a single namespace,
624  * but there is one important drawback. The batch direct protocol will not proxy to a different
625  * server node when the mapped node has migrated a record to another node (resulting in not
626  * found record).
627  * <p>
628  * This can happen after a node has been added/removed from the cluster and there is a lag
629  * between records being migrated and client partition map update (once per second).
630  * <p>
631  * The new batch index protocol will perform this record proxy when necessary.
632  * Default: false (use new batch index protocol if server supports it)
633  */
635 
636  /**
637  * Allow batch to be processed immediately in the server's receiving thread when the server
638  * deems it to be appropriate. If false, the batch will always be processed in separate
639  * transaction threads. This field is only relevant for the new batch index protocol.
640  * <p>
641  * For batch exists or batch reads of smaller sized records (<= 1K per record), inline
642  * processing will be significantly faster on "in memory" namespaces. The server disables
643  * inline processing on disk based namespaces regardless of this policy field.
644  * <p>
645  * Inline processing can introduce the possibility of unfairness because the server
646  * can process the entire batch before moving onto the next command.
647  * Default: true
648  */
650 
652 
653 /**
654  * Administration Policy
655  *
656  * @ingroup client_policies
657  */
658 typedef struct as_policy_admin_s {
659 
660  /**
661  * Maximum time in milliseconds to wait for
662  * the operation to complete.
663  */
664  uint32_t timeout;
665 
667 
668 /**
669  * Struct of all policy values and operation policies.
670  *
671  * This is utilizes by as_config, to define global and default values
672  * for policies.
673  *
674  * @ingroup as_config_t
675  */
676 typedef struct as_policies_s {
677 
678  /***************************************************************************
679  * DEFAULT VALUES, IF SPECIFIC POLICY IS UNDEFINED
680  **************************************************************************/
681 
682  /**
683  * Default timeout in milliseconds.
684  *
685  * Will be used if specific policies have a timeout of 0 (zero).
686  *
687  * The default value is `AS_POLICY_TIMEOUT_DEFAULT`.
688  */
689  uint32_t timeout;
690 
691  /**
692  * Specifies the behavior for failed operations.
693  *
694  * The default value is `AS_POLICY_RETRY_DEFAULT`.
695  */
697 
698  /**
699  * Specifies the behavior for the key.
700  *
701  * The default value is `AS_POLICY_KEY_DEFAULT`.
702  */
704 
705  /**
706  * Specifies the behavior for the generation
707  * value.
708  *
709  * The default value is `AS_POLICY_GEN_DEFAULT`.
710  */
712 
713  /**
714  * Specifies the behavior for the existence
715  * of the record.
716  *
717  * The default value is `AS_POLICY_EXISTS_DEFAULT`.
718  */
720 
721  /**
722  * Specifies which replica to read.
723  *
724  * The default value is `AS_POLICY_REPLICA_MASTER`.
725  */
727 
728  /**
729  * Specifies the consistency level for reading.
730  *
731  * The default value is `AS_POLICY_CONSISTENCY_LEVEL_ONE`.
732  */
734 
735  /**
736  * Specifies the commit level for writing.
737  *
738  * The default value is `AS_POLICY_COMMIT_LEVEL_ALL`.
739  */
741 
742  /***************************************************************************
743  * SPECIFIC POLICIES
744  **************************************************************************/
745 
746  /**
747  * The default read policy.
748  */
750 
751  /**
752  * The default write policy.
753  */
755 
756  /**
757  * The default operate policy.
758  */
760 
761  /**
762  * The default remove policy.
763  */
765 
766  /**
767  * The default apply policy.
768  */
770 
771  /**
772  * The default query policy.
773  */
775 
776  /**
777  * The default scan policy.
778  */
780 
781  /**
782  * The default info policy.
783  */
785 
786  /**
787  * The default batch policy.
788  */
790 
791  /**
792  * The default administration policy.
793  */
795 
796 } as_policies;
797 
798 /******************************************************************************
799  * FUNCTIONS
800  *****************************************************************************/
801 
802 /**
803  * Initialize as_policy_read to default values.
804  *
805  * @param p The policy to initialize.
806  * @return The initialized policy.
807  *
808  * @relates as_policy_read
809  */
810 static inline as_policy_read*
812 {
817  return p;
818 }
819 
820 /**
821  * Copy as_policy_read values.
822  *
823  * @param src The source policy.
824  * @param trg The target policy.
825  *
826  * @relates as_policy_read
827  */
828 static inline void
830 {
831  trg->timeout = src->timeout;
832  trg->key = src->key;
833  trg->replica = src->replica;
835 }
836 
837 /**
838  * Initialize as_policy_write to default values.
839  *
840  * @param p The policy to initialize.
841  * @return The initialized policy.
842  *
843  * @relates as_policy_write
844  */
845 static inline as_policy_write*
847 {
854  return p;
855 }
856 
857 /**
858  * Copy as_policy_write values.
859  *
860  * @param src The source policy.
861  * @param trg The target policy.
862  *
863  * @relates as_policy_write
864  */
865 static inline void
867 {
868  trg->timeout = src->timeout;
869  trg->retry = src->retry;
870  trg->key = src->key;
871  trg->gen = src->gen;
872  trg->exists = src->exists;
873  trg->commit_level = src->commit_level;
874 }
875 
876 /**
877  * Initialize as_policy_operate to default values.
878  *
879  * @param p The policy to initialize.
880  * @return The initialized policy.
881  *
882  * @relates as_policy_operate
883  */
884 static inline as_policy_operate*
886 {
894  return p;
895 }
896 
897 /**
898  * Copy as_policy_operate values.
899  *
900  * @param src The source policy.
901  * @param trg The target policy.
902  *
903  * @relates as_policy_operate
904  */
905 static inline void
907 {
908  trg->timeout = src->timeout;
909  trg->retry = src->retry;
910  trg->key = src->key;
911  trg->gen = src->gen;
912  trg->replica = src->replica;
914  trg->commit_level = src->commit_level;
915 }
916 
917 /**
918  * Initialize as_policy_remove to default values.
919  *
920  * @param p The policy to initialize.
921  * @return The initialized policy.
922  *
923  * @relates as_policy_remove
924  */
925 static inline as_policy_remove*
927 {
932  p->generation = 0;
934  return p;
935 }
936 
937 /**
938  * Copy as_policy_remove values.
939  *
940  * @param src The source policy.
941  * @param trg The target policy.
942  *
943  * @relates as_policy_remove
944  */
945 static inline void
947 {
948  trg->timeout = src->timeout;
949  trg->retry = src->retry;
950  trg->key = src->key;
951  trg->gen = src->gen;
952  trg->generation = src->generation;
953  trg->commit_level = src->commit_level;
954 }
955 
956 /**
957  * Initialize as_policy_apply to default values.
958  *
959  * @param p The policy to initialize.
960  * @return The initialized policy.
961  *
962  * @relates as_policy_apply
963  */
964 static inline as_policy_apply*
966 {
970  p->ttl = 0; // AS_RECORD_DEFAULT_TTL
971  return p;
972 }
973 
974 /**
975  * Copy as_policy_apply values.
976  *
977  * @param src The source policy.
978  * @param trg The target policy.
979  *
980  * @relates as_policy_apply
981  */
982 static inline void
984 {
985  trg->timeout = src->timeout;
986  trg->key = src->key;
987  trg->commit_level = src->commit_level;
988  trg->ttl = src->ttl;
989 }
990 
991 /**
992  * Initialize as_policy_info to default values.
993  *
994  * @param p The policy to initialize.
995  * @return The initialized policy.
996  *
997  * @relates as_policy_info
998  */
999 static inline as_policy_info*
1001 {
1003  p->send_as_is = true;
1004  p->check_bounds = true;
1005  return p;
1006 }
1007 
1008 /**
1009  * Copy as_policy_info values.
1010  *
1011  * @param src The source policy.
1012  * @param trg The target policy.
1013  *
1014  * @relates as_policy_info
1015  */
1016 static inline void
1018 {
1019  trg->timeout = src->timeout;
1020  trg->send_as_is = src->send_as_is;
1021  trg->check_bounds = src->check_bounds;
1022 }
1023 
1024 /**
1025  * Initialize as_policy_batch to default values.
1026  *
1027  * @param p The policy to initialize.
1028  * @return The initialized policy.
1029  *
1030  * @relates as_policy_batch
1031  */
1032 static inline as_policy_batch*
1034 {
1036  p->concurrent = false;
1037  p->use_batch_direct = false;
1038  p->allow_inline = true;
1039  return p;
1040 }
1041 
1042 /**
1043  * Copy as_policy_batch values.
1044  *
1045  * @param src The source policy.
1046  * @param trg The target policy.
1047  *
1048  * @relates as_policy_batch
1049  */
1050 static inline void
1052 {
1053  trg->timeout = src->timeout;
1054  trg->concurrent = src->concurrent;
1055  trg->use_batch_direct = src->use_batch_direct;
1056  trg->allow_inline = src->allow_inline;
1057 }
1058 
1059 /**
1060  * Initialize as_policy_admin to default values.
1061  *
1062  * @param p The policy to initialize.
1063  * @return The initialized policy.
1064  *
1065  * @relates as_policy_admin
1066  */
1067 static inline as_policy_admin*
1069 {
1071  return p;
1072 }
1073 
1074 /**
1075  * Copy as_policy_admin values.
1076  *
1077  * @param src The source policy.
1078  * @param trg The target policy.
1079  *
1080  * @relates as_policy_admin
1081  */
1082 static inline void
1084 {
1085  trg->timeout = src->timeout;
1086 }
1087 
1088 /**
1089  * Initialize as_policy_scan to default values.
1090  *
1091  * @param p The policy to initialize.
1092  * @return The initialized policy.
1093  *
1094  * @relates as_policy_scan
1095  */
1096 static inline as_policy_scan*
1098 {
1099  p->timeout = 0;
1100  p->fail_on_cluster_change = false;
1101  return p;
1102 }
1103 
1104 /**
1105  * Copy as_policy_scan values.
1106  *
1107  * @param src The source policy.
1108  * @param trg The target policy.
1109  *
1110  * @relates as_policy_scan
1111  */
1112 static inline void
1114 {
1115  trg->timeout = src->timeout;
1117 }
1118 
1119 /**
1120  * Initialize as_policy_query to default values.
1121  *
1122  * @param p The policy to initialize.
1123  * @return The initialized policy.
1124  *
1125  * @relates as_policy_query
1126  */
1127 static inline as_policy_query*
1129 {
1130  p->timeout = 0;
1131  return p;
1132 }
1133 
1134 /**
1135  * Copy as_policy_query values.
1136  *
1137  * @param src The source policy.
1138  * @param trg The target policy.
1139  *
1140  * @relates as_policy_query
1141  */
1142 static inline void
1144 {
1145  trg->timeout = src->timeout;
1146 }
1147 
1148 /**
1149  * Initialize as_policies to undefined values.
1150  * as_policies_resolve() will later be called resolve undefined values to global defaults.
1151  *
1152  * @param p The policies to undefine
1153  * @return The undefined policies.
1154  *
1155  * @relates as_policies
1156  */
1157 as_policies*
1159 
1160 /**
1161  * Resolve global policies (like timeout) with operational policies (like as_policy_read).
1162  *
1163  * @param p The policies to resolve
1164  *
1165  * @relates as_policies
1166  */
1167 void
1169 
1170 #ifdef __cplusplus
1171 } // end extern "C"
1172 #endif