CLOSE_WAIT
Active close를 client가 하는 경우 Passive close를 하는 서버측에서는
CLOSE_WAIT 상태에 이를수 있다.
반대로 Active close하는 클라이언트 측은 FIN_WAIT2 상태에서 대기하다가 일정시간(net.ipv4.tcp_fin_timeout ; 2*Maximum Segment Lifetime= 60sec)에서 TIME_WAIT 상태가 된다.
FIN_WAIT2(커널옵션으로)나 TIME_WAIT(고정값?)은 타임아웃처리가 가능하나 CLOSE_WAIT은 close해주는 작업이 필요하다...
- CLOSE_WAIT 상태 : 어플리케이션에서 close()를 적절하게 처리해주지 못하면, TCP 포트는 CLOSE_WAIT 상태로 계속 기다리게 된다. 이렇게 CLOSE_WAIT 상태가 statement에 많아지게 되면, Hang 이 걸려 더이상 연결을 하지 못하는 경우가 생기기도 한다. 따라서 어플리케이션 개발시 여러 상황에 따라 close() 처리를 잘 해줘야 한다.
SIGPIPE 받아서 close 해주거나
아니면 socket api의 리턴값을 체크해서 close를 해주는 코드 추가
signal(SIGPIPE, to_exit);
signal(SIGHUP, to_exit);
signal(SIGINT, to_exit);
signal(SIGQUIT, to_exit);
signal(SIGABRT, to_exit);
signal(SIGTERM, to_exit);
signal(SIGSEGV, to_exit);
signal(SIGBUS, to_exit);
Long breathing
2015년 6월 21일 일요일
단상
현재 위치를 정확히 인지하고 하고자하는 목표가 있다면 그 목표에 도달하기 위해서 무엇이 필요한지 나열해보자...
- 일요일 오전에는 독서하자
- 출퇴근 이동 중에 짤막한 글(10페이지 이내)을 읽자
- 아침 업무 시작전에 마인드맵으로 정리하자
- 일요일 오전에는 독서하자
- 출퇴근 이동 중에 짤막한 글(10페이지 이내)을 읽자
- 아침 업무 시작전에 마인드맵으로 정리하자
2015년 4월 29일 수요일
OCI Prepare - Bind rowid
OCILIB supports the Oracle ROWID type through C scalar string types (dtext).
- ROWIDs can be retrieved from resultset with OCI_GetString()
- ROWIDs can be binded to statements with OCI_BindString()
- Example
#include "ocilib.h" int main(void) { OCI_Connection *cn; OCI_Statement *st1, *st2; OCI_Resultset *rs; char rowid[OCI_SIZE_ROWID+1]; int value; if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT)) return EXIT_FAILURE; cn = OCI_ConnectionCreate("db", "usr", "pwd", OCI_SESSION_DEFAULT); st1 = OCI_StatementCreate(cn); st2 = OCI_StatementCreate(cn); OCI_Prepare(st1, "update test_fetch set code = :i where rowid = :s"); OCI_BindInt(st1, ":i", &value); OCI_BindString(st1, ":s", rowid, sizeof(rowid)-1); OCI_ExecuteStmt(st2, "select code, rowid from test_fetch for update"); rs = OCI_GetResultset(st2); while (OCI_FetchNext(rs)) { value = OCI_GetInt(rs, 1); strcpy(rowid, OCI_GetString(rs, 2)); /* updating value with some computation ... */ value = (value + 4 ) % 2; OCI_Execute(st1); } OCI_Commit(cn); OCI_Cleanup(); return EXIT_SUCCESS; }
OCI returning - Register
Detailed Description
OCILIB supports the Oracle feature 'Returning into' for DML statements.
Let's Oracle talk about this features:
- 'Using the RETURNING clause with a DML statement allows you to essentially combine two SQL statements into one, possibly saving you a server round-trip. This is accomplished by adding an extra clause to the traditional UPDATE, INSERT, and DELETE statements. The extra clause effectively adds a query to the DML statement. In the OCI, the values are returned to the application through the use of OUT bind variables.'
OCILIB implements this features by providing a set of functions that allows to register output placeholders for the returned values. Once the DML is executed with OCI_Execute(), the output returned data is available through a regular resultset object that can be fetched.
- Note:
- Array binding interface is also supported with 'returning into' DML statement. Every iteration (or row of given arrays) generates an resultset object. Once a resultset is fetched, the next on can be retrieved with OCI_GetNextResultset()
- Note:
- OCI_Long are not supported for 'returning into' clause .This is a limitation imposed by Oracle.
- OCI_Column objects retrieved from output OCI_Resultset have the following particularities:
- their names are the provided bind names to the DML statement (by example, ':out1'). So any call to the functions OCI_GetXXX2() should be aware of it
- The columns detailed SQL attributes might be not all set or accurate. By example, the scale and precision are not set, the SQL type is the one chosen by OCILIB regarding the OCILIB object datatype and might be slightly different from the real one.
- Example
#include "ocilib.h" int main(void) { OCI_Connection *cn; OCI_Statement *st; OCI_Resultset *rs; if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT)) return EXIT_FAILURE; cn = OCI_ConnectionCreate("db", "usr", "pwd", OCI_SESSION_DEFAULT); st = OCI_StatementCreate(cn); OCI_Prepare(st, "update products set code = code+10 returning code into :i"); OCI_RegisterInt(st, ":i"); OCI_Execute(st); rs = OCI_GetResultset(st); while (OCI_FetchNext(rs)) printf("%i\n", OCI_GetInt(rs, 1)); printf("count : %i\n", OCI_GetRowCount(rs)); OCI_Commit(cn); OCI_Cleanup(); return EXIT_SUCCESS; }
OCI Queue async - Advanced Queuing
Detailed Description
OCILIB supports Oracle Advanced Queues features
Let's Oracle talk about this features !
- Oracle Queues (from Oracle Streams - Advanced Queuing User's Guide)
Oracle Streams AQ provides database-integrated message queuing functionality. It is built on top of Oracle Streams and leverages the functions of Oracle Database so that messages can be stored persistently, propagated between queues on different computers and databases, and transmitted using Oracle Net Services and HTTP(S). Because Oracle Streams AQ is implemented in database tables, all operational benefits of high availability, scalability, and reliability are also applicable to queue data. Standard database features such as recovery, restart, and security are supported by Oracle Streams AQ. You can use database development and management tools such as Oracle Enterprise Manager to monitor queues. Like other database tables, queue tables can be imported and exported.
- OCILIB implementation
OCILIB provides a (nearly) full C implementation of Advanced Queues available in Oracle OCI and proposes the following datatypes :
- OCI_Msg : Implementation of message to enqueue/dequeue from/to queues
- OCI_Enqueue : Implementation of enqueuing process
- OCI_Dequeue : Implementation of dequeuing process
- OCI_Agent : Implementation of Advanced queues Agents
Note that the only AQ features not supported yet by OCILIB are :
- Payloads of type AnyData
- Enqueuing/dequeuing arrays of messages
- Optionnal delivery mode introduced in 10gR2
OCILIB provides as well a C API to administrate queues and queue tables initially reserved to PL/SQL and Java (wrappers around PL/SQL calls). This API, based on internal PL/SQL calls wrapping the DBMS_AQADM packages procedures, allow the following actions :
- create, alter, drop and purge queue tables (OCI_QueueTableXXX calls)
- create, alter, drop, start, stop queues (OCI_QueueXXX calls)
Note that the user connected to the database needs particular privileges to manipulate or administrate queues (See Oracle Streams - Advanced Queuing User's Guide for more informations on these privileges)
- Example
#include "ocilib.h" int main(int argc, char *argv[]) { OCI_Connection *con; OCI_Enqueue *enq; OCI_Dequeue *deq; OCI_Msg *msg; OCI_TypeInfo *inf; OCI_Object *obj; OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT); con = OCI_ConnectionCreate("db", "usr", "pwd", OCI_SESSION_DEFAULT); inf = OCI_TypeInfoGet(con, "MY_MESSAGE", OCI_TIF_TYPE); enq = OCI_EnqueueCreate(inf, "my_queue"); deq = OCI_DequeueCreate(inf, "my_queue"); msg = OCI_MsgCreate(inf); obj = OCI_ObjectCreate(con, inf); OCI_ObjectSetString(obj, "TITLE", "NEXT MEETING"); OCI_ObjectSetString(obj, "CONTENT", "12:00 PM IN STARBUCKS"); OCI_MsgSetObject(msg, obj); OCI_EnqueuePut(enq, msg); OCI_MsgFree(msg); OCI_ObjectFree(obj); OCI_Commit(con); msg = OCI_DequeueGet(deq); obj = OCI_MsgGetObject(msg); printf("MSG '%s' => %s\n", OCI_ObjectGetString(obj, "TITLE"), OCI_ObjectGetString(obj, "CONTENT")); OCI_EnqueueFree(enq); OCI_DequeueFree(deq); OCI_ConnectionFree(con); OCI_Cleanup(); return EXIT_SUCCESS; }
OCI Subscribtion register
Detailed Description
OCILIB supports Oracle 10gR2 feature Database Change Notifications (DCN) also named Continuous Query Notifications (CQN)
This features allows a client application to register notifications when some changes are made in a database :
- Database status changes : startup and shutdown
- Database objects changes :
- DDL changes : alter or drop actions
- DML changes : insert, delete, update actions
This feature can be really useful in applications that hold a cache of data. Instead of refreshing data periodically by connecting to the server, the application could only refresh modified data when necessary or perform specific tasks depending on the events. It saves application time, network traffic and can help the design of the application logic.
The database status change notification is also interesting to be informed of instance startup / shutdown
Check Oracle documentation for more details about this feature
- Note:
- No active database connection is required to receive the notifications as they are handled by the Oracle client using a dedicated socket connection to the server
- Dabatase changes
The client application can be notified of any database status change (single DB or multiple DB in a RAC environment).
- Object changes
The notifications of object changes are based on the registration of a query ('select' SQL statement).
Oracle server will notify of any changes of any object that is part of the statement result set.
Registering a statement will notify about any changes on its result set rows performed after the registration of the query.
The query can be a simple 'select * from table' or a complex query involving many tables and/or criteria in the where clause.
For Object changes, the notification can be at :
- At Object level : only the object name (schema + object) is given
- At row level : same that object level + RowID of the altered row
- Warning:
- Trying to use this features with a client/server version < 10gR2 will raise an error
- Example
#include "ocilib.h" #ifdef _WINDOWS #define sleep(x) Sleep(x*1000) #endif #define wait_for_events() sleep(5) void event_handler(OCI_Event *event); void error_handler(OCI_Error *err); int main(void) { OCI_Connection *con; OCI_Subscription *sub; OCI_Statement *st; printf("=> Initializing OCILIB in event mode...\n\n"); if (!OCI_Initialize(error_handler, NULL, OCI_ENV_EVENTS)) return EXIT_FAILURE; printf("=> Connecting to usr@db...\n\n"); con = OCI_ConnectionCreate("db", "usr", "pwd", OCI_SESSION_DEFAULT); OCI_SetAutoCommit(con, TRUE); printf("=> Creating statement...\n\n"); st = OCI_StatementCreate(con); printf("=> Creating tables...\n\n"); OCI_ExecuteStmt(st, "create table table1(code number)"); OCI_ExecuteStmt(st, "create table table2(str varchar2(10))"); printf("=> Registering subscription...\n\n"); sub = OCI_SubscriptionRegister(con, "sub-00", OCI_CNT_ALL, event_handler, 5468, 0); printf("=> Adding queries to be notified...\n\n"); OCI_Prepare(st, "select * from table1"); OCI_SubscriptionAddStatement(sub, st); OCI_Prepare(st, "select * from table2"); OCI_SubscriptionAddStatement(sub, st); printf("=> Executing some DDL operation...\n\n"); OCI_ExecuteStmt(st, "alter table table1 add price number"); wait_for_events(); printf("=> Executing some DML operation...\n\n"); OCI_ExecuteStmt(st, "insert into table1 values(1, 10.5)"); OCI_ExecuteStmt(st, "insert into table2 values('shoes')"); OCI_ExecuteStmt(st, "update table1 set price = 13.5 where code = 1"); OCI_ExecuteStmt(st, "delete from table2 "); wait_for_events(); printf("=> Droping tables...\n\n"); OCI_ExecuteStmt(st, "drop table table1"); OCI_ExecuteStmt(st, "drop table table2"); wait_for_events(); printf("=> Disconnecting from DB...\n\n"); OCI_ConnectionFree(con); printf("=> Stopping the remote database...\n\n"); OCI_DatabaseShutdown("db", "sys", "sys", OCI_SESSION_SYSDBA, OCI_DB_SDM_FULL, OCI_DB_SDF_IMMEDIATE); wait_for_events();; printf("=> Starting the remote database...\n\n"); OCI_DatabaseStartup("db", "sys", "sys", OCI_SESSION_SYSDBA, OCI_DB_SPM_FULL, OCI_DB_SPF_FORCE, NULL); wait_for_events(); printf("=> Unregistering subscription...\n\n"); OCI_SubscriptionUnregister(sub); printf("=> Cleaning up OCILIB resources...\n\n"); OCI_Cleanup(); printf("=> Done...\n\n"); return EXIT_SUCCESS; } void error_handler(OCI_Error *err) { int err_type = OCI_ErrorGetType(err); const char *err_msg = OCI_ErrorGetString(err); printf("** %s - %s\n", err_type == OCI_ERR_WARNING ? "Warning" : "Error", err_msg); } void event_handler(OCI_Event *event) { unsigned int type = OCI_EventGetType(event); unsigned int op = OCI_EventGetOperation(event); OCI_Subscription *sub = OCI_EventGetSubscription(event); printf("** Notification : %s\n\n", OCI_SubscriptionGetName(sub)); printf("...... Database : %s\n", OCI_EventGetDatabase(event)); switch (type) { case OCI_ENT_STARTUP: printf("...... Event : Startup\n"); break; case OCI_ENT_SHUTDOWN: printf("...... Event : Shutdown\n"); break; case OCI_ENT_SHUTDOWN_ANY: printf("...... Event : Shutdown any\n"); break; case OCI_ENT_DROP_DATABASE: printf("...... Event : drop database\n"); break; case OCI_ENT_DEREGISTER: printf("...... Event : deregister\n"); break; case OCI_ENT_OBJECT_CHANGED: printf("...... Event : object changed\n"); printf("........... Object : %s\n", OCI_EventGetObject(event)); switch (op) { case OCI_ONT_INSERT: printf("........... Action : insert\n"); break; case OCI_ONT_UPDATE: printf("........... Action : update\n"); break; case OCI_ONT_DELETE: printf("........... Action : delete\n"); break; case OCI_ONT_ALTER: printf("........... Action : alter\n"); break; case OCI_ONT_DROP: printf("........... Action : drop\n"); break; } if (op < OCI_ONT_ALTER) printf("........... Rowid : %s\n", OCI_EventGetRowid(event)); break; } printf("\n"); }
OCI Hash table
Detailed Description
OCILIB uses hash tables internally for index/name columns mapping.
OCILIB makes public its hash table�s implementation public for general purpose uses.
OCI_HashTable objects manage string keys / values that can be :
- integers
- strings
- pointers
This hash table implementation :
- handle collisions
- allows multiple values per key
- Internal conception
- The hash table is composed of an array of slots.
- Each slot can hold a linked list of entries (one per key)
- Each entry can hold a linked list of values
- Note:
- The internal hash function computes the index in the array where the entry has to be inserted/looked up.
- Collisions are handled by chaining method.
#include "ocilib.h" int main(void) { int i, n; OCI_Connection *cn; OCI_Statement *st; OCI_Resultset *rs; OCI_HashTable *table; OCI_HashEntry *e; OCI_HashValue *v; if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT)) return EXIT_FAILURE; cn = OCI_ConnectionCreate("db", "usr", "pwd", OCI_SESSION_DEFAULT); st = OCI_StatementCreate(cn); table = OCI_HashCreate(256, OCI_HASH_INTEGER); /* fill the hash table with data from DB */ OCI_ExecuteStmt(st, "select code, name from products"); rs = OCI_GetResultset(st); while (OCI_FetchNext(rs)) OCI_HashAddInt(table, OCI_GetString2(rs, "name"), OCI_GetInt2(rs, "code")); printf("%d row(s) fetched\n", OCI_GetRowCount(rs)); /* lookup an entry */ printf("code for %s is : %d\n", "Cars", OCI_HashGetInt(table, "Cars")); /* browse the hash table */ n = OCI_HashGetSize(table); for (i = 0; i < n; i++) { e = OCI_HashGetEntry(table, i); while (e != NULL) { printf (">key: '%s'\n", e->key); v = e->values; while (v != NULL) { printf ("..... value : '%i'\n", v->value.num); v = v->next; } e = e->next; } } /* destroy table */ OCI_HashFree(table); OCI_Cleanup(); return EXIT_SUCCESS; }
피드 구독하기:
글 (Atom)