Example #1
0
// NewClient initializes a hyperdex client ready to use.
//
// For every call to NewClient, there must be a call to Destroy.
//
// Panics when the internal looping goroutine receives an error from hyperdex.
//
// Example:
// 		client, err := hyperdex_client.NewClient("127.0.0.1", 1234)
// 		if err != nil {
//			//handle error
//		}
//		defer client.Destroy()
//		// use client
func NewClient(ip string, port int) (*Client, error) {
	C_client := C.hyperdex_client_create(C.CString(ip), C.uint16_t(port))
	C_arena := C.hyperdex_ds_arena_create()

	if C_client == nil {
		return nil, fmt.Errorf("Could not create hyperdex_client (ip=%s, port=%d)", ip, port)
	}
	client := &Client{
		C_client,
		C_arena,
		make([]request, 0, 8), // No reallocation within 8 concurrent requests to hyperdex_client_loop
		make(chan struct{}, 1),
	}

	go func() {
		for {
			select {
			// quit goroutine when client is destroyed
			case <-client.closeChan:
				return
			default:
				// check if there are pending requests
				// and only if there are, call hyperdex_client_loop
				if len(client.requests) > 0 {
					var status C.enum_hyperdex_client_returncode
					ret := int64(C.hyperdex_client_loop(client.ptr, C.int(TIMEOUT), &status))
					//log.Printf("hyperdex_client_loop(%X, %d, %X) -> %d\n", unsafe.Pointer(client.ptr), hyperdex_client_loop_timeout, unsafe.Pointer(&status), ret)
					if ret < 0 {
						panic(newInternalError(status,
							C.GoString(C.hyperdex_client_error_message(client.ptr))).Error())
					}
					// find processed request among pending requests
					for i, req := range client.requests {
						if req.id == ret {
							log.Printf("Processing request %v\n", req.id)
							log.Printf("Loop status: %v\n", status)
							log.Printf("Request status: %v\n", *req.status)
							if status == C.HYPERDEX_CLIENT_SUCCESS {
								switch *req.status {
								case C.HYPERDEX_CLIENT_SUCCESS:
									log.Println("Request success")
									if req.success != nil {
										req.success()
									}
									if req.isIterator {
										// We want to break out at here so that the
										// request won't get removed
										goto SKIP_DELETING_REQUEST
									} else if req.complete != nil {
										// We want to break out at here so that the
										// request won't get removed
										req.complete()
									}
								case C.HYPERDEX_CLIENT_SEARCHDONE:
									log.Println("Request search done")
									if req.complete != nil {
										req.complete()
									}
								case C.HYPERDEX_CLIENT_CMPFAIL:
									log.Println("Comparison failure")
									if req.failure != nil {
										req.failure(*req.status,
											C.GoString(C.hyperdex_client_error_message(client.ptr)))
									}
								default:
									log.Println("Request failure")
									if req.failure != nil {
										req.failure(*req.status,
											C.GoString(C.hyperdex_client_error_message(client.ptr)))
									}
								}
							} else if req.failure != nil {
								req.failure(status,
									C.GoString(C.hyperdex_client_error_message(client.ptr)))
							}
							client.requests = append(client.requests[:i], client.requests[i+1:]...)
						SKIP_DELETING_REQUEST:
							break
						}
					}
				}
				// prevent other goroutines from starving
				runtime.Gosched()
			}
		}
		panic("Should not be reached: end of infinite loop")
	}()

	return client, nil
}
Example #2
0
// Generic operation that returns errors
func (client *Client) errOp(funcName, space, key string, attrs Attributes, conds []Condition) ErrorChannel {
	errCh := make(chan error, CHANNEL_BUFFER_SIZE)
	var status C.enum_hyperdex_client_returncode
	var C_attrs *C.struct_hyperdex_client_attribute
	var C_attrs_sz C.size_t
	var C_map_attrs *C.struct_hyperdex_client_map_attribute
	var C_map_attrs_sz C.size_t
	var C_attr_checks *C.struct_hyperdex_client_attribute_check
	var C_attr_checks_sz C.size_t
	var err error

	if conds != nil {
		C_attr_checks, C_attr_checks_sz, err = client.newCAttributeCheckList(conds)
		if err != nil {
			errCh <- err
			close(errCh)
			return errCh
		}
	}

	if attrs != nil {
		// Check if it's a map operation
		if strings.Contains(funcName, "map") {
			// Annoyingly, some map functions expect hyperdex_client_attribute
			// rather than hyperdex_client_map_attribute, so we need to further check:
			switch funcName {
			case "map_remove", "cond_map_remove":
				C_attrs, C_attrs_sz, err = client.newCAttributeListFromMaps(attrs)
			default:
				C_map_attrs, C_map_attrs_sz, err = client.newCMapAttributeList(attrs)
			}
		} else {
			C_attrs, C_attrs_sz, err = client.newCAttributeList(attrs)
		}
		if err != nil {
			errCh <- err
			close(errCh)
			return errCh
		}
	}

	var req_id int64
	switch funcName {
	case "put":
		req_id = int64(C.hyperdex_client_put(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attrs, C_attrs_sz, &status))
	case "cond_put":
		req_id = int64(C.hyperdex_client_cond_put(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attr_checks, C_attr_checks_sz,
			C_attrs, C_attrs_sz, &status))
	case "put_if_not_exist":
		req_id = int64(C.hyperdex_client_put_if_not_exist(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attrs, C_attrs_sz, &status))
	case "del":
		req_id = int64(C.hyperdex_client_del(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)), &status))
	case "cond_del":
		req_id = int64(C.hyperdex_client_cond_del(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attr_checks, C_attr_checks_sz, &status))
	case "atomic_add":
		req_id = int64(C.hyperdex_client_atomic_add(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attrs, C_attrs_sz, &status))
	case "cond_atomic_add":
		req_id = int64(C.hyperdex_client_cond_atomic_add(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attr_checks, C_attr_checks_sz,
			C_attrs, C_attrs_sz, &status))
	case "atomic_sub":
		req_id = int64(C.hyperdex_client_atomic_sub(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attrs, C_attrs_sz, &status))
	case "cond_atomic_sub":
		req_id = int64(C.hyperdex_client_cond_atomic_sub(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attr_checks, C_attr_checks_sz,
			C_attrs, C_attrs_sz, &status))
	case "atomic_mul":
		req_id = int64(C.hyperdex_client_atomic_mul(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attrs, C_attrs_sz, &status))
	case "cond_atomic_mul":
		req_id = int64(C.hyperdex_client_cond_atomic_mul(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attr_checks, C_attr_checks_sz,
			C_attrs, C_attrs_sz, &status))
	case "atomic_div":
		req_id = int64(C.hyperdex_client_atomic_div(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attrs, C_attrs_sz, &status))
	case "cond_atomic_div":
		req_id = int64(C.hyperdex_client_cond_atomic_div(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attr_checks, C_attr_checks_sz,
			C_attrs, C_attrs_sz, &status))
	case "atomic_mod":
		req_id = int64(C.hyperdex_client_atomic_mod(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attrs, C_attrs_sz, &status))
	case "cond_atomic_mod":
		req_id = int64(C.hyperdex_client_cond_atomic_mod(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attr_checks, C_attr_checks_sz,
			C_attrs, C_attrs_sz, &status))
	case "atomic_and":
		req_id = int64(C.hyperdex_client_atomic_and(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attrs, C_attrs_sz, &status))
	case "cond_atomic_and":
		req_id = int64(C.hyperdex_client_cond_atomic_and(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attr_checks, C_attr_checks_sz,
			C_attrs, C_attrs_sz, &status))
	case "atomic_or":
		req_id = int64(C.hyperdex_client_atomic_or(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attrs, C_attrs_sz, &status))
	case "cond_atomic_or":
		req_id = int64(C.hyperdex_client_cond_atomic_or(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attr_checks, C_attr_checks_sz,
			C_attrs, C_attrs_sz, &status))
	case "atomic_xor":
		req_id = int64(C.hyperdex_client_atomic_xor(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attrs, C_attrs_sz, &status))
	case "cond_atomic_xor":
		req_id = int64(C.hyperdex_client_cond_atomic_xor(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attr_checks, C_attr_checks_sz,
			C_attrs, C_attrs_sz, &status))
	case "string_prepend":
		req_id = int64(C.hyperdex_client_string_prepend(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attrs, C_attrs_sz, &status))
	case "cond_string_prepend":
		req_id = int64(C.hyperdex_client_cond_string_prepend(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attr_checks, C_attr_checks_sz,
			C_attrs, C_attrs_sz, &status))
	case "string_append":
		req_id = int64(C.hyperdex_client_string_append(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attrs, C_attrs_sz, &status))
	case "cond_string_append":
		req_id = int64(C.hyperdex_client_cond_string_append(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attr_checks, C_attr_checks_sz,
			C_attrs, C_attrs_sz, &status))
	case "list_lpush":
		req_id = int64(C.hyperdex_client_list_lpush(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attrs, C_attrs_sz, &status))
	case "cond_list_lpush":
		req_id = int64(C.hyperdex_client_cond_list_lpush(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attr_checks, C_attr_checks_sz,
			C_attrs, C_attrs_sz, &status))
	case "list_rpush":
		req_id = int64(C.hyperdex_client_list_rpush(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attrs, C_attrs_sz, &status))
	case "cond_list_rpush":
		req_id = int64(C.hyperdex_client_cond_list_rpush(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attr_checks, C_attr_checks_sz,
			C_attrs, C_attrs_sz, &status))
	case "set_add":
		req_id = int64(C.hyperdex_client_set_add(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attrs, C_attrs_sz, &status))
	case "cond_set_add":
		req_id = int64(C.hyperdex_client_cond_set_add(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attr_checks, C_attr_checks_sz,
			C_attrs, C_attrs_sz, &status))
	case "set_remove":
		req_id = int64(C.hyperdex_client_set_remove(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attrs, C_attrs_sz, &status))
	case "cond_set_remove":
		req_id = int64(C.hyperdex_client_cond_set_remove(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attr_checks, C_attr_checks_sz,
			C_attrs, C_attrs_sz, &status))
	case "set_intersect":
		req_id = int64(C.hyperdex_client_set_intersect(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attrs, C_attrs_sz, &status))
	case "cond_set_intersect":
		req_id = int64(C.hyperdex_client_cond_set_intersect(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attr_checks, C_attr_checks_sz,
			C_attrs, C_attrs_sz, &status))
	case "set_union":
		req_id = int64(C.hyperdex_client_set_union(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attrs, C_attrs_sz, &status))
	case "cond_set_union":
		req_id = int64(C.hyperdex_client_cond_set_union(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_attr_checks, C_attr_checks_sz,
			C_attrs, C_attrs_sz, &status))
	case "map_add":
		req_id = int64(C.hyperdex_client_map_add(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			C_map_attrs, C_map_attrs_sz, &status))
	default:
		panic(fmt.Sprintf("Unsupported function: %s", funcName))
	}

	if req_id < 0 {
		errCh <- newInternalError(status,
			C.GoString(C.hyperdex_client_error_message(client.ptr)))
		close(errCh)
		return errCh
	}

	req := request{
		id:     req_id,
		status: &status,
		success: func() {
			errCh <- nil
			close(errCh)
		},
		failure: errChannelFailureCallback(errCh),
		complete: func() {
			// TODO: The invocation of hyperdex_client_destroy_attrs causes
			// memory error.  But not destroying the C struct list might
			// cause potential memory leak.

			// println("put complete callback")
			// C_attrs := *req.bundle["C_attrs"].(**C.struct_hyperdex_client_attribute)
			// C_attrs_sz := *req.bundle["C_attrs_sz"].(*C.size_t)
			// if C_attrs_sz > 0 {
			// 	println("BP8")
			// 	C.hyperdex_client_destroy_attrs(C_attrs, C_attrs_sz)
			// 	println("BP9")
			// 	//log.Printf("hyperdex_client_destroy_attrs(%X, %d)\n", unsafe.Pointer(C_attrs), C_attrs_sz)
			// }
		},
	}

	client.requests = append(client.requests, req)
	return errCh
}
Example #3
0
// Generic operation that returns objects
func (client *Client) objOp(funcName, space, key string, conds []Condition) ObjectChannel {
	objCh := make(chan Object, CHANNEL_BUFFER_SIZE)
	var status C.enum_hyperdex_client_returncode
	var C_attrs *C.struct_hyperdex_client_attribute
	var C_attrs_sz C.size_t
	var C_attr_checks *C.struct_hyperdex_client_attribute_check
	var C_attr_checks_sz C.size_t
	var err error

	if conds != nil {
		C_attr_checks, C_attr_checks_sz, err = client.newCAttributeCheckList(conds)
		if err != nil {
			objCh <- Object{
				Err: err,
			}
			close(objCh)
			return objCh
		}
	}

	var req_id int64
	switch funcName {
	case "get":
		req_id = int64(C.hyperdex_client_get(client.ptr, C.CString(space),
			C.CString(key), C.size_t(bytesOf(key)),
			&status, &C_attrs, &C_attrs_sz))
	case "search":
		req_id = int64(C.hyperdex_client_search(client.ptr,
			C.CString(space), C_attr_checks, C_attr_checks_sz,
			&status, &C_attrs, &C_attrs_sz))
	}

	if req_id < 0 {
		objCh <- Object{Err: newInternalError(status,
			C.GoString(C.hyperdex_client_error_message(client.ptr)))}
		close(objCh)
		return objCh
	}

	req := request{
		id:     req_id,
		status: &status,
	}
	switch funcName {
	case "get":
		req.success = func() {
			attrs, err := client.newAttributeListFromC(C_attrs, C_attrs_sz)
			if err != nil {
				objCh <- Object{Err: err}
				close(objCh)
				return
			}
			objCh <- Object{Err: nil, Key: key, Attrs: attrs}
			close(objCh)
			if C_attrs_sz > 0 {
				C.hyperdex_client_destroy_attrs(C_attrs, C_attrs_sz)
			}
		}
		req.failure = objChannelFailureCallback(objCh)
	case "search":
		req.isIterator = true
		req.success = func() {
			// attrs, err := newAttributeListFromC(C_attrs, C_attrs_sz)
			attrs, err := client.newAttributeListFromC(C_attrs, C_attrs_sz)
			if err != nil {
				objCh <- Object{Err: err}
				close(objCh)
				return
			}

			if C_attrs_sz > 0 {
				C.hyperdex_client_destroy_attrs(C_attrs, C_attrs_sz)
			}
			objCh <- Object{Attrs: attrs}
		}
		req.failure = objChannelFailureCallback(objCh)
		req.complete = func() {
			close(objCh)
		}
	}

	client.requests = append(client.requests, req)
	return objCh
}
Example #4
0
func (client *Client) SortedSearch(space string, conds []Condition, sort_by string,
	limit int, maxmin int) ObjectChannel {

	objCh := make(chan Object, CHANNEL_BUFFER_SIZE)
	var status C.enum_hyperdex_client_returncode
	var C_attrs *C.struct_hyperdex_client_attribute
	var C_attrs_sz C.size_t
	var C_attr_checks *C.struct_hyperdex_client_attribute_check
	var C_attr_checks_sz C.size_t
	var err error

	if conds != nil {
		C_attr_checks, C_attr_checks_sz, err = client.newCAttributeCheckList(conds)
		if err != nil {
			objCh <- Object{
				Err: err,
			}
			close(objCh)
			return objCh
		}
	}

	req_id := int64(C.hyperdex_client_sorted_search(client.ptr,
		C.CString(space), C_attr_checks, C_attr_checks_sz,
		C.CString(sort_by), C.uint64_t(limit), C.int(maxmin),
		&status, &C_attrs, &C_attrs_sz))

	if req_id < 0 {
		objCh <- Object{Err: newInternalError(status,
			C.GoString(C.hyperdex_client_error_message(client.ptr)))}
		close(objCh)
		return objCh
	}

	req := request{
		id:         req_id,
		status:     &status,
		isIterator: true,
		success: func() {
			// attrs, err := newAttributeListFromC(C_attrs, C_attrs_sz)
			attrs, err := client.newAttributeListFromC(C_attrs, C_attrs_sz)
			if err != nil {
				objCh <- Object{Err: err}
				close(objCh)
				return
			}

			if C_attrs_sz > 0 {
				C.hyperdex_client_destroy_attrs(C_attrs, C_attrs_sz)
			}
			objCh <- Object{Attrs: attrs}
		},
		failure: objChannelFailureCallback(objCh),
		complete: func() {
			close(objCh)
		},
	}

	client.requests = append(client.requests, req)
	return objCh
}