diff options
Diffstat (limited to 'storage/ndb/src/common/util')
36 files changed, 8781 insertions, 0 deletions
diff --git a/storage/ndb/src/common/util/Base64.cpp b/storage/ndb/src/common/util/Base64.cpp new file mode 100644 index 00000000000..3db911f481f --- /dev/null +++ b/storage/ndb/src/common/util/Base64.cpp @@ -0,0 +1,212 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <ndb_global.h> +#include <Base64.hpp> + +static char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + +int +base64_encode(const UtilBuffer &src, BaseString &dst) +{ + return base64_encode(src.get_data(), src.length(), dst); +} + +int +base64_encode(const void * _s, size_t src_len, BaseString &dst) { + const unsigned char * s = (const unsigned char*)_s; + size_t i = 0; + size_t len = 0; + while(i < src_len) { + if(len == 76){ + len = 0; + dst.append('\n'); + } + + unsigned c; + c = s[i++]; + c <<= 8; + + if(i < src_len) + c += s[i]; + c <<= 8; + i++; + + if(i < src_len) + c += s[i]; + i++; + + dst.append(base64_table[(c >> 18) & 0x3f]); + dst.append(base64_table[(c >> 12) & 0x3f]); + + if(i > (src_len + 1)) + dst.append('='); + else + dst.append(base64_table[(c >> 6) & 0x3f]); + + if(i > src_len) + dst.append('='); + else + dst.append(base64_table[(c >> 0) & 0x3f]); + + len += 4; + } + return 0; +} + +static inline unsigned +pos(unsigned char c) { + return strchr(base64_table, c) - base64_table; +} + + +int +base64_decode(const BaseString &src, UtilBuffer &dst) { + return base64_decode(src.c_str(), src.length(), dst); +} + +#define SKIP_SPACE(src, i, size){ \ + while(i < size && isspace(* src)){ \ + i++; \ + src++; \ + } \ + if(i == size){ \ + i = size + 1; \ + break; \ + } \ +} + +int +base64_decode(const char * src, size_t size, UtilBuffer &dst) { + size_t i = 0; + while(i < size){ + unsigned c = 0; + int mark = 0; + + SKIP_SPACE(src, i, size); + + c += pos(*src++); + c <<= 6; + i++; + + SKIP_SPACE(src, i, size); + + c += pos(*src++); + c <<= 6; + i++; + + SKIP_SPACE(src, i, size); + + if(* src != '=') + c += pos(*src++); + else { + i = size; + mark = 2; + c <<= 6; + goto end; + } + c <<= 6; + i++; + + SKIP_SPACE(src, i, size); + + if(*src != '=') + c += pos(*src++); + else { + i = size; + mark = 1; + goto end; + } + i++; + + end: + char b[3]; + b[0] = (c >> 16) & 0xff; + b[1] = (c >> 8) & 0xff; + b[2] = (c >> 0) & 0xff; + + dst.append((void *)b, 3-mark); + } + + if(i != size){ + abort(); + return -1; + } + return 0; +} + +#ifdef __TEST__B64 +/** + * USER_FLAGS="-D__TEST__B64" make Base64.o && g++ Base64.o BaseString.o + */ +inline +void +require(bool b){ + if(!b) + abort(); +} + +int +main(void){ + for(int i = 0; i < 500; i++){ + const size_t len = rand() % 10000 + 1; + UtilBuffer src; + for(size_t j = 0; j<len; j++){ + char c = rand(); + src.append(&c, 1); + } + require(src.length() == len); + + BaseString str; + require(base64_encode(src, str) == 0); + + if(str.length() == 3850){ + printf(">%s<\n", str.c_str()); + } + + UtilBuffer dst; + require(base64_decode(str, dst) == 0); + require(dst.length() == src.length()); + + const char * c_src = (char*)src.get_data(); + const char * c_dst = (char*)dst.get_data(); + if(memcmp(src.get_data(), dst.get_data(), src.length()) != 0){ + printf("-- src --\n"); + for(int i2 = 0; i2<len; i2++){ + unsigned char c = c_src[i2]; + printf("%.2x ", (unsigned)c); + if((i2 % 8) == 7) + printf("\n"); + } + printf("\n"); + + printf("-- dst --\n"); + for(int i2 = 0; i2<len; i2++){ + unsigned char c = c_dst[i2]; + printf("%.2x ", (unsigned)c); + if((i2 % 8) == 7) + printf("\n"); + } + printf("\n"); + abort(); + } + } + return 0; +} + +#endif diff --git a/storage/ndb/src/common/util/BaseString.cpp b/storage/ndb/src/common/util/BaseString.cpp new file mode 100644 index 00000000000..dbff44c377d --- /dev/null +++ b/storage/ndb/src/common/util/BaseString.cpp @@ -0,0 +1,434 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* -*- c-basic-offset: 4; -*- */ +#include <ndb_global.h> +#include <BaseString.hpp> +#include <basestring_vsnprintf.h> + +BaseString::BaseString() +{ + m_chr = new char[1]; + m_chr[0] = 0; + m_len = 0; +} + +BaseString::BaseString(const char* s) +{ + const size_t n = strlen(s); + m_chr = new char[n + 1]; + memcpy(m_chr, s, n + 1); + m_len = n; +} + +BaseString::BaseString(const BaseString& str) +{ + const char* const s = str.m_chr; + const size_t n = str.m_len; + char* t = new char[n + 1]; + memcpy(t, s, n + 1); + m_chr = t; + m_len = n; +} + +BaseString::~BaseString() +{ + delete[] m_chr; +} + +BaseString& +BaseString::assign(const char* s) +{ + const size_t n = strlen(s); + char* t = new char[n + 1]; + memcpy(t, s, n + 1); + delete[] m_chr; + m_chr = t; + m_len = n; + return *this; +} + +BaseString& +BaseString::assign(const char* s, size_t n) +{ + char* t = new char[n + 1]; + memcpy(t, s, n); + t[n] = 0; + delete[] m_chr; + m_chr = t; + m_len = n; + return *this; +} + +BaseString& +BaseString::assign(const BaseString& str, size_t n) +{ + if (n > str.m_len) + n = str.m_len; + return assign(str.m_chr, n); +} + +BaseString& +BaseString::append(const char* s) +{ + const size_t n = strlen(s); + char* t = new char[m_len + n + 1]; + memcpy(t, m_chr, m_len); + memcpy(t + m_len, s, n + 1); + delete[] m_chr; + m_chr = t; + m_len += n; + return *this; +} + +BaseString& +BaseString::append(char c) { + return appfmt("%c", c); +} + +BaseString& +BaseString::append(const BaseString& str) +{ + return append(str.m_chr); +} + +BaseString& +BaseString::append(const Vector<BaseString> &vector, + const BaseString &separator) { + for(size_t i=0;i<vector.size(); i++) { + append(vector[i]); + if(i<vector.size()-1) + append(separator); + } + return *this; +} + +BaseString& +BaseString::assfmt(const char *fmt, ...) +{ + char buf[1]; + va_list ap; + int l; + + /* Figure out how long the formatted string will be. A small temporary + * buffer is used, because I don't trust all implementations to work + * when called as vsnprintf(NULL, 0, ...). + */ + va_start(ap, fmt); + l = basestring_vsnprintf(buf, sizeof(buf), fmt, ap) + 1; + va_end(ap); + if(l > (int)m_len) { + delete[] m_chr; + m_chr = new char[l]; + } + va_start(ap, fmt); + basestring_vsnprintf(m_chr, l, fmt, ap); + va_end(ap); + m_len = strlen(m_chr); + return *this; +} + +BaseString& +BaseString::appfmt(const char *fmt, ...) +{ + char buf[1]; + va_list ap; + int l; + + /* Figure out how long the formatted string will be. A small temporary + * buffer is used, because I don't trust all implementations to work + * when called as vsnprintf(NULL, 0, ...). + */ + va_start(ap, fmt); + l = basestring_vsnprintf(buf, sizeof(buf), fmt, ap) + 1; + va_end(ap); + char *tmp = new char[l]; + va_start(ap, fmt); + basestring_vsnprintf(tmp, l, fmt, ap); + va_end(ap); + append(tmp); + delete[] tmp; + return *this; +} + +BaseString& +BaseString::operator=(const BaseString& str) +{ + if (this != &str) { + this->assign(str); + } + return *this; +} + +int +BaseString::split(Vector<BaseString> &v, + const BaseString &separator, + int maxSize) const { + char *str = strdup(m_chr); + int i, start, len, num = 0; + len = strlen(str); + for(start = i = 0; + (i <= len) && ( (maxSize<0) || ((int)v.size()<=maxSize-1) ); + i++) { + if(strchr(separator.c_str(), str[i]) || i == len) { + if(maxSize < 0 || (int)v.size() < maxSize-1) + str[i] = '\0'; + v.push_back(BaseString(str+start)); + num++; + start = i+1; + } + } + free(str); + + return num; +} + +ssize_t +BaseString::indexOf(char c) { + char *p; + p = strchr(m_chr, c); + if(p == NULL) + return -1; + return (ssize_t)(p-m_chr); +} + +ssize_t +BaseString::lastIndexOf(char c) { + char *p; + p = strrchr(m_chr, c); + if(p == NULL) + return -1; + return (ssize_t)(p-m_chr); +} + +BaseString +BaseString::substr(ssize_t start, ssize_t stop) { + if(stop < 0) + stop = length(); + ssize_t len = stop-start; + if(len <= 0) + return BaseString(""); + BaseString s; + s.assign(m_chr+start, len); + return s; +} + +static bool +iswhite(char c) { + switch(c) { + case ' ': + case '\t': + return true; + default: + return false; + } + /* NOTREACHED */ +} + +char ** +BaseString::argify(const char *argv0, const char *src) { + Vector<char *> vargv; + + if(argv0 != NULL) + vargv.push_back(strdup(argv0)); + + char *tmp = new char[strlen(src)+1]; + char *dst = tmp; + const char *end = src + strlen(src); + /* Copy characters from src to destination, while compacting them + * so that all whitespace is compacted and replaced by a NUL-byte. + * At the same time, add pointers to strings in the vargv vector. + * When whitespace is detected, the characters '"' and '\' are honored, + * to make it possible to give arguments containing whitespace. + * The semantics of '"' and '\' match that of most Unix shells. + */ + while(src < end && *src) { + /* Skip initial whitespace */ + while(src < end && *src && iswhite(*src)) + src++; + + char *begin = dst; + while(src < end && *src) { + /* Handle '"' quotation */ + if(*src == '"') { + src++; + while(src < end && *src && *src != '"') { + if(*src == '\\') + src++; + *dst++ = *src++; + } + src++; + if(src >= end) + goto end; + } + + /* Handle '\' */ + if(*src == '\\') + src++; + else if(iswhite(*src)) + break; + + /* Actually copy characters */ + *dst++ = *src++; + } + + /* Make sure the string is properly terminated */ + *dst++ = '\0'; + src++; + + vargv.push_back(strdup(begin)); + } + end: + + delete[] tmp; + vargv.push_back(NULL); + + /* Convert the C++ Vector into a C-vector of strings, suitable for + * calling execv(). + */ + char **argv = (char **)malloc(sizeof(*argv) * (vargv.size())); + if(argv == NULL) + return NULL; + + for(size_t i = 0; i < vargv.size(); i++){ + argv[i] = vargv[i]; + } + + return argv; +} + +BaseString& +BaseString::trim(const char * delim){ + trim(m_chr, delim); + m_len = strlen(m_chr); + return * this; +} + +char* +BaseString::trim(char * str, const char * delim){ + int len = strlen(str) - 1; + for(; len > 0 && strchr(delim, str[len]); len--); + + int pos = 0; + for(; pos <= len && strchr(delim, str[pos]); pos++); + + if(pos > len){ + str[0] = 0; + return 0; + } else { + memmove(str, &str[pos], len - pos + 1); + str[len-pos+1] = 0; + } + + return str; +} + +int +BaseString::vsnprintf(char *str, size_t size, const char *format, va_list ap) +{ + return(basestring_vsnprintf(str, size, format, ap)); +} + +int +BaseString::snprintf(char *str, size_t size, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + int ret= basestring_vsnprintf(str, size, format, ap); + va_end(ap); + return(ret); +} + + +#ifdef TEST_BASE_STRING + +/* +g++ -g -Wall -o tbs -DTEST_BASE_STRING -I$NDB_TOP/include/util \ + -I$NDB_TOP/include/portlib BaseString.cpp +valgrind ./tbs +*/ + +int main() +{ + BaseString s("abc"); + BaseString t(s); + s.assign("def"); + t.append("123"); + assert(s == "def"); + assert(t == "abc123"); + s.assign(""); + t.assign(""); + for (unsigned i = 0; i < 1000; i++) { + s.append("xyz"); + t.assign(s); + assert(strlen(t.c_str()) % 3 == 0); + } + + { + BaseString s(":123:abc:;:foo:"); + Vector<BaseString> v; + assert(s.split(v, ":;") == 7); + + assert(v[0] == ""); + assert(v[1] == "123"); + assert(v[2] == "abc"); + assert(v[3] == ""); + assert(v[4] == ""); + assert(v[5] == "foo"); + assert(v[6] == ""); + } + + { + BaseString s(":123:abc:foo:bar"); + Vector<BaseString> v; + assert(s.split(v, ":;", 4) == 4); + + assert(v[0] == ""); + assert(v[1] == "123"); + assert(v[2] == "abc"); + assert(v[3] == "foo:bar"); + + BaseString n; + n.append(v, "()"); + assert(n == "()123()abc()foo:bar"); + n = ""; + n.append(v); + assert(n == " 123 abc foo:bar"); + } + + { + assert(BaseString("hamburger").substr(4,2) == ""); + assert(BaseString("hamburger").substr(3) == "burger"); + assert(BaseString("hamburger").substr(4,8) == "urge"); + assert(BaseString("smiles").substr(1,5) == "mile"); + assert(BaseString("012345").indexOf('2') == 2); + assert(BaseString("hej").indexOf('X') == -1); + } + + { + assert(BaseString(" 1").trim(" ") == "1"); + assert(BaseString("1 ").trim(" ") == "1"); + assert(BaseString(" 1 ").trim(" ") == "1"); + assert(BaseString("abc\t\n\r kalleabc\t\r\n").trim("abc\t\r\n ") == "kalle"); + assert(BaseString(" ").trim(" ") == ""); + } + return 0; +} + +#endif + +template class Vector<char *>; +template class Vector<BaseString>; diff --git a/storage/ndb/src/common/util/Bitmask.cpp b/storage/ndb/src/common/util/Bitmask.cpp new file mode 100644 index 00000000000..0aa39a37204 --- /dev/null +++ b/storage/ndb/src/common/util/Bitmask.cpp @@ -0,0 +1,351 @@ +#include <Bitmask.hpp> +#include <NdbOut.hpp> + +static +void print(const Uint32 src[], Uint32 len, Uint32 pos = 0) +{ + printf("b'"); + for(unsigned i = 0; i<len; i++) + { + if(BitmaskImpl::get((pos + len + 31) >> 5, src, i+pos)) + printf("1"); + else + printf("0"); + if((i & 31) == 31) + printf(" "); + } +} + +#ifndef __TEST_BITMASK__ + +void +BitmaskImpl::getFieldImpl(const Uint32 src[], + unsigned shiftL, unsigned len, Uint32 dst[]) +{ + assert(shiftL < 32); + + unsigned shiftR = 32 - shiftL; + unsigned undefined = shiftL ? ~0 : 0; + + * dst = shiftL ? * dst : 0; + + while(len >= 32) + { + * dst++ |= (* src) << shiftL; + * dst = ((* src++) >> shiftR) & undefined; + len -= 32; + } + + if(len < shiftR) + { + * dst |= ((* src) & ((1 << len) - 1)) << shiftL; + } + else + { + * dst++ |= ((* src) << shiftL); + * dst = ((* src) >> shiftR) & ((1 << (len - shiftR)) - 1) & undefined; + } +} + +void +BitmaskImpl::setFieldImpl(Uint32 dst[], + unsigned shiftL, unsigned len, const Uint32 src[]) +{ + /** + * + * abcd ef00 + * 00ab cdef + */ + assert(shiftL < 32); + unsigned shiftR = 32 - shiftL; + unsigned undefined = shiftL ? ~0 : 0; + while(len >= 32) + { + * dst = (* src++) >> shiftL; + * dst++ |= ((* src) << shiftR) & undefined; + len -= 32; + } + + Uint32 mask = ((1 << len) -1); + * dst = (* dst & ~mask); + if(len < shiftR) + { + * dst |= ((* src++) >> shiftL) & mask; + } + else + { + * dst |= ((* src++) >> shiftL); + * dst |= ((* src) & ((1 << (len - shiftR)) - 1)) << shiftR ; + } +} +#else + +#define DEBUG 0 +#include <Vector.hpp> +static void do_test(int bitmask_size); + +int +main(int argc, char** argv) +{ + int loops = argc > 1 ? atoi(argv[1]) : 1000; + int max_size = argc > 2 ? atoi(argv[2]) : 1000; + + + for(int i = 0; i<loops; i++) + do_test(1 + (rand() % max_size)); +} + +struct Alloc +{ + Uint32 pos; + Uint32 size; + Vector<Uint32> data; +}; + +static void require(bool b) +{ + if(!b) abort(); +} + +static +bool cmp(const Uint32 b1[], const Uint32 b2[], Uint32 len) +{ + Uint32 sz32 = (len + 31) >> 5; + for(int i = 0; i<len; i++) + { + if(BitmaskImpl::get(sz32, b1, i) ^ BitmaskImpl::get(sz32, b2, i)) + return false; + } + return true; +} + + +static int val_pos = 0; +static int val[] = { 384, 241, 32, + 1,1,1,1, 0,0,0,0, 1,1,1,1, 0,0,0,0, + 241 }; + +static int lrand() +{ +#if 0 + return val[val_pos++]; +#else + return rand(); +#endif +} + +static +void rand(Uint32 dst[], Uint32 len) +{ + for(int i = 0; i<len; i++) + BitmaskImpl::set((len + 31) >> 5, dst, i, (lrand() % 1000) > 500); +} + +static +void simple(int pos, int size) +{ + ndbout_c("simple pos: %d size: %d", pos, size); + Vector<Uint32> _mask; + Vector<Uint32> _src; + Vector<Uint32> _dst; + Uint32 sz32 = (size + pos + 32) >> 5; + const Uint32 sz = 4 * sz32; + + Uint32 zero = 0; + _mask.fill(sz32+1, zero); + _src.fill(sz32+1, zero); + _dst.fill(sz32+1, zero); + + Uint32 * src = _src.getBase(); + Uint32 * dst = _dst.getBase(); + Uint32 * mask = _mask.getBase(); + + memset(src, 0x0, sz); + memset(dst, 0x0, sz); + memset(mask, 0xFF, sz); + rand(src, size); + BitmaskImpl::setField(sz32, mask, pos, size, src); + BitmaskImpl::getField(sz32, mask, pos, size, dst); + printf("src: "); print(src, size+31); printf("\n"); + printf("msk: "); print(mask, (sz32 << 5) + 31); printf("\n"); + printf("dst: "); print(dst, size+31); printf("\n"); + require(cmp(src, dst, size+31)); +}; + +static +void simple2(int size, int loops) +{ + ndbout_c("simple2 %d - ", size); + Vector<Uint32> _mask; + Vector<Uint32> _src; + Vector<Uint32> _dst; + + Uint32 sz32 = (size + 32) >> 5; + Uint32 sz = sz32 << 2; + + Uint32 zero = 0; + _mask.fill(sz32+1, zero); + _src.fill(sz32+1, zero); + _dst.fill(sz32+1, zero); + + Uint32 * src = _src.getBase(); + Uint32 * dst = _dst.getBase(); + Uint32 * mask = _mask.getBase(); + + Vector<Uint32> save; + for(int i = 0; i<loops; i++) + { + memset(mask, 0xFF, sz); + memset(dst, 0xFF, sz); + int len; + int pos = 0; + while(pos+1 < size) + { + memset(src, 0xFF, sz); + while(!(len = rand() % (size - pos))); + BitmaskImpl::setField(sz32, mask, pos, len, src); + if(memcmp(dst, mask, sz)) + { + ndbout_c("pos: %d len: %d", pos, len); + print(mask, size); + abort(); + } + printf("[ %d %d ]", pos, len); + save.push_back(pos); + save.push_back(len); + pos += len; + } + + for(int j = 0; j<save.size(); ) + { + pos = save[j++]; + len = save[j++]; + memset(src, 0xFF, sz); + BitmaskImpl::getField(sz32, mask, pos, len, src); + if(memcmp(dst, src, sz)) + { + ndbout_c("pos: %d len: %d", pos, len); + printf("src: "); print(src, size); printf("\n"); + printf("dst: "); print(dst, size); printf("\n"); + printf("msk: "); print(mask, size); printf("\n"); + abort(); + } + } + ndbout_c(""); + } +} + +static void +do_test(int bitmask_size) +{ +#if 1 + simple(rand() % 33, (rand() % 63)+1); +//#else + Vector<Alloc> alloc_list; + bitmask_size = (bitmask_size + 31) & ~31; + Uint32 sz32 = (bitmask_size >> 5); + Vector<Uint32> alloc_mask; + Vector<Uint32> test_mask; + + ndbout_c("Testing bitmask of size %d", bitmask_size); + Uint32 zero = 0; + alloc_mask.fill(sz32, zero); + test_mask.fill(sz32, zero); + + for(int i = 0; i<5000; i++) + { + Vector<Uint32> tmp; + tmp.fill(sz32, zero); + + int pos = lrand() % (bitmask_size - 1); + int free = 0; + if(BitmaskImpl::get(sz32, alloc_mask.getBase(), pos)) + { + // Bit was allocated + // 1) Look up allocation + // 2) Check data + // 3) free it + size_t j; + int min, max; + for(j = 0; j<alloc_list.size(); j++) + { + min = alloc_list[j].pos; + max = min + alloc_list[j].size; + if(pos >= min && pos < max) + { + break; + } + } + require(pos >= min && pos < max); + BitmaskImpl::getField(sz32, test_mask.getBase(), min, max-min, + tmp.getBase()); + if(DEBUG) + { + printf("freeing [ %d %d ]", min, max); + printf("- mask: "); + print(tmp.getBase(), max - min); + + printf(" save: "); + size_t k; + Alloc& a = alloc_list[j]; + for(k = 0; k<a.data.size(); k++) + printf("%.8x ", a.data[k]); + printf("\n"); + } + int bytes = (max - min + 7) >> 3; + if(!cmp(tmp.getBase(), alloc_list[j].data.getBase(), max - min)) + { + abort(); + } + while(min < max) + BitmaskImpl::clear(sz32, alloc_mask.getBase(), min++); + alloc_list.erase(j); + } + else + { + Vector<Uint32> tmp; + tmp.fill(sz32, zero); + + // Bit was free + // 1) Check how much space is avaiable + // 2) Create new allocation of lrandom size + // 3) Fill data with lrandom data + // 4) Update alloc mask + while(pos+free < bitmask_size && + !BitmaskImpl::get(sz32, alloc_mask.getBase(), pos+free)) + free++; + + Uint32 sz = + (free <= 64 && ((lrand() % 100) > 80)) ? free : (lrand() % free); + sz = sz ? sz : 1; + sz = pos + sz == bitmask_size ? sz - 1 : sz; + Alloc a; + a.pos = pos; + a.size = sz; + a.data.fill(((sz+31)>> 5)-1, zero); + if(DEBUG) + printf("pos %d -> alloc [ %d %d ]", pos, pos, pos+sz); + for(size_t j = 0; j<sz; j++) + { + BitmaskImpl::set(sz32, alloc_mask.getBase(), pos+j); + if((lrand() % 1000) > 500) + BitmaskImpl::set((sz + 31) >> 5, a.data.getBase(), j); + } + if(DEBUG) + { + printf("- mask: "); + print(a.data.getBase(), sz); + printf("\n"); + } + BitmaskImpl::setField(sz32, test_mask.getBase(), pos, sz, + a.data.getBase()); + alloc_list.push_back(a); + } + } +#endif +} + +template class Vector<Alloc>; +template class Vector<Uint32>; + +#endif diff --git a/storage/ndb/src/common/util/ConfigValues.cpp b/storage/ndb/src/common/util/ConfigValues.cpp new file mode 100644 index 00000000000..5c4b17c73ca --- /dev/null +++ b/storage/ndb/src/common/util/ConfigValues.cpp @@ -0,0 +1,748 @@ + +#include <ndb_global.h> +#include <ConfigValues.hpp> +#include <NdbOut.hpp> +#include <NdbTCP.h> + +static Uint32 hash(Uint32 key, Uint32 size); +static Uint32 nextHash(Uint32 key, Uint32 size, Uint32 pos, Uint32 count); +static bool findKey(const Uint32 * vals, Uint32 sz, Uint32 key, Uint32 * pos); + +/** + * Key + * + * t = Type - 4 bits 0-15 + * s = Section - 14 bits 0-16383 + * k = Key value - 14 bits 0-16383 + * + * 1111111111222222222233 + * 01234567890123456789012345678901 + * kkkkkkkkkkkkkkssssssssssssssoooo + */ +#define KP_TYPE_MASK (15) +#define KP_TYPE_SHIFT (28) +#define KP_SECTION_MASK (0x3FFF) +#define KP_SECTION_SHIFT (14) +#define KP_KEYVAL_MASK (0x3FFF) +#define KP_KEYVAL_SHIFT (0) +#define KP_MASK (0x0FFFFFFF) + +static const Uint32 CFV_KEY_PARENT = (KP_KEYVAL_MASK - 1); +static const Uint32 CFV_KEY_FREE = ~0; + +static const char Magic[] = { 'N', 'D', 'B', 'C', 'O', 'N', 'F', 'V' }; + +//#define DEBUG_CV +#ifdef DEBUG_CV +#define DEBUG +#else +#define DEBUG if(0) +#endif + +inline +ConfigValues::ValueType +getTypeOf(Uint32 k) { + return (ConfigValues::ValueType)((k >> KP_TYPE_SHIFT) & KP_TYPE_MASK); +} + +ConfigValues::ConfigValues(Uint32 sz, Uint32 dsz){ + m_size = sz; + m_dataSize = dsz; + m_stringCount = 0; + m_int64Count = 0; + for(Uint32 i = 0; i<m_size; i++){ + m_values[i << 1] = CFV_KEY_FREE; + } +} + +ConfigValues::~ConfigValues(){ + for(Uint32 i = 0; i<m_stringCount; i++){ + free(* getString(i)); + } +} + +bool +ConfigValues::ConstIterator::get(Uint32 key, Entry * result) const { + Uint32 pos; + if(!findKey(m_cfg.m_values, m_cfg.m_size, key | m_currentSection, &pos)){ + return false; + } + + result->m_key = key; + return m_cfg.getByPos(pos, result); +} + +bool +ConfigValues::getByPos(Uint32 pos, Entry * result) const { + assert(pos < (2 * m_size)); + Uint32 keypart = m_values[pos]; + Uint32 val = m_values[pos+1]; + + switch(::getTypeOf(keypart)){ + case IntType: + case SectionType: + result->m_int = val; + break; + case StringType: + result->m_string = * getString(val); + break; + case Int64Type: + result->m_int64 = * get64(val); + break; + case InvalidType: + default: + return false; + } + + result->m_type = ::getTypeOf(keypart); + + return true; +} + +Uint64 * +ConfigValues::get64(Uint32 index) const { + assert(index < m_int64Count); + const Uint32 * data = m_values + (m_size << 1); + Uint64 * ptr = (Uint64*)data; + ptr += index; + return ptr; +} + +char ** +ConfigValues::getString(Uint32 index) const { + assert(index < m_stringCount); + const Uint32 * data = m_values + (m_size << 1); + char * ptr = (char*)data; + ptr += m_dataSize; + ptr -= (index * sizeof(char *)); + return (char**)ptr; +} + +bool +ConfigValues::ConstIterator::openSection(Uint32 key, Uint32 no){ + Uint32 curr = m_currentSection; + + Entry tmp; + if(get(key, &tmp) && tmp.m_type == SectionType){ + m_currentSection = tmp.m_int; + if(get(no, &tmp) && tmp.m_type == IntType){ + m_currentSection = tmp.m_int; + /** + * Validate + */ + if(get(CFV_KEY_PARENT, &tmp)){ + return true; + } + } + } + + m_currentSection = curr; + return false; +} + +bool +ConfigValues::ConstIterator::closeSection() { + + Entry tmp; + if(get(CFV_KEY_PARENT, &tmp) && tmp.m_type == IntType){ + m_currentSection = tmp.m_int; + return true; + } + + return false; +} + +bool +ConfigValues::Iterator::set(Uint32 key, Uint32 value){ + Uint32 pos; + if(!findKey(m_cfg.m_values, m_cfg.m_size, key | m_currentSection, &pos)){ + return false; + } + + if(::getTypeOf(m_cfg.m_values[pos]) != IntType){ + return false; + } + + m_cfg.m_values[pos+1] = value; + return true; +} + +bool +ConfigValues::Iterator::set(Uint32 key, Uint64 value){ + Uint32 pos; + if(!findKey(m_cfg.m_values, m_cfg.m_size, key | m_currentSection, &pos)){ + return false; + } + + if(::getTypeOf(m_cfg.m_values[pos]) != Int64Type){ + return false; + } + + * m_cfg.get64(m_cfg.m_values[pos+1]) = value; + return true; +} + +bool +ConfigValues::Iterator::set(Uint32 key, const char * value){ + Uint32 pos; + if(!findKey(m_cfg.m_values, m_cfg.m_size, key | m_currentSection, &pos)){ + return false; + } + + if(::getTypeOf(m_cfg.m_values[pos]) != StringType){ + return false; + } + + char ** str = m_cfg.getString(m_cfg.m_values[pos+1]); + free(* str); + * str = strdup(value ? value : ""); + return true; +} + +static +bool +findKey(const Uint32 * values, Uint32 sz, Uint32 key, Uint32 * _pos){ + Uint32 pos = hash(key, sz); + Uint32 count = 0; + while((values[pos] & KP_MASK) != key && count < sz){ + pos = nextHash(key, sz, pos, ++count); + } + + if((values[pos] & KP_MASK)== key){ + *_pos = pos; + return true; + } + return false; +} + +static +Uint32 +hash(Uint32 key, Uint32 size){ + Uint32 tmp = (key >> 16) ^ (key & 0xFFFF); + return (((tmp << 16) | tmp) % size) << 1; +} + +static +Uint32 +nextHash(Uint32 key, Uint32 size, Uint32 pos, Uint32 count){ + Uint32 p = (pos >> 1); + if((key % size) != 0) + p += key; + else + p += 1; + return (p % size) << 1; +} + +static +Uint32 +directory(Uint32 sz){ + const Uint32 _input = sz; + if((sz & 1) == 0) + sz ++; + + bool prime = false; + while(!prime){ + prime = true; + for(Uint32 n = 3; n*n <= sz; n += 2){ + if((sz % n) == 0){ + prime = false; + sz += 2; + break; + } + } + } + DEBUG printf("directory %d -> %d\n", _input, sz); + return sz; +} + +ConfigValuesFactory::ConfigValuesFactory(Uint32 keys, Uint32 data){ + m_sectionCounter = (1 << KP_SECTION_SHIFT); + m_freeKeys = directory(keys); + m_freeData = (data + 7) & ~7; + m_currentSection = 0; + m_cfg = create(m_freeKeys, m_freeData); +} + +ConfigValuesFactory::ConfigValuesFactory(ConfigValues * cfg){ + m_cfg = cfg; + m_freeKeys = 0; + m_freeData = m_cfg->m_dataSize; + m_sectionCounter = (1 << KP_SECTION_SHIFT); + m_currentSection = 0; + const Uint32 sz = 2 * m_cfg->m_size; + for(Uint32 i = 0; i<sz; i += 2){ + const Uint32 key = m_cfg->m_values[i]; + if(key == CFV_KEY_FREE){ + m_freeKeys++; + } else { + switch(::getTypeOf(key)){ + case ConfigValues::IntType: + case ConfigValues::SectionType: + break; + case ConfigValues::Int64Type: + m_freeData -= sizeof(Uint64); + break; + case ConfigValues::StringType: + m_freeData -= sizeof(char *); + break; + case ConfigValues::InvalidType: + abort(); + } + Uint32 sec = key & (KP_SECTION_MASK << KP_SECTION_SHIFT); + m_sectionCounter = (sec > m_sectionCounter ? sec : m_sectionCounter); + } + } +} + +ConfigValues * +ConfigValuesFactory::create(Uint32 keys, Uint32 data){ + Uint32 sz = sizeof(ConfigValues); + sz += (2 * keys * sizeof(Uint32)); + sz += data; + + void * tmp = malloc(sz); + return new (tmp) ConfigValues(keys, data); +} + +void +ConfigValuesFactory::expand(Uint32 fk, Uint32 fs){ + if(m_freeKeys >= fk && m_freeData >= fs){ + return ; + } + + m_freeKeys = (m_freeKeys >= fk ? m_cfg->m_size : fk + m_cfg->m_size); + m_freeData = (m_freeData >= fs ? m_cfg->m_dataSize : fs + m_cfg->m_dataSize); + m_freeKeys = directory(m_freeKeys); + m_freeData = (m_freeData + 7) & ~7; + + ConfigValues * m_tmp = m_cfg; + m_cfg = create(m_freeKeys, m_freeData); + put(* m_tmp); + m_tmp->~ConfigValues(); + free(m_tmp); +} + +void +ConfigValuesFactory::shrink(){ + if(m_freeKeys == 0 && m_freeData == 0){ + return ; + } + + m_freeKeys = m_cfg->m_size - m_freeKeys; + m_freeData = m_cfg->m_dataSize - m_freeData; + m_freeKeys = directory(m_freeKeys); + m_freeData = (m_freeData + 7) & ~7; + + ConfigValues * m_tmp = m_cfg; + m_cfg = create(m_freeKeys, m_freeData); + put(* m_tmp); + m_tmp->~ConfigValues(); + free(m_tmp); +} + +bool +ConfigValuesFactory::openSection(Uint32 key, Uint32 no){ + ConfigValues::Entry tmp; + const Uint32 parent = m_currentSection; + + ConfigValues::ConstIterator iter(* m_cfg); + iter.m_currentSection = m_currentSection; + if(!iter.get(key, &tmp)){ + + tmp.m_key = key; + tmp.m_type = ConfigValues::SectionType; + tmp.m_int = m_sectionCounter; + m_sectionCounter += (1 << KP_SECTION_SHIFT); + + if(!put(tmp)){ + return false; + } + } + + if(tmp.m_type != ConfigValues::SectionType){ + return false; + } + + m_currentSection = tmp.m_int; + + tmp.m_key = no; + tmp.m_type = ConfigValues::IntType; + tmp.m_int = m_sectionCounter; + if(!put(tmp)){ + m_currentSection = parent; + return false; + } + m_sectionCounter += (1 << KP_SECTION_SHIFT); + + m_currentSection = tmp.m_int; + tmp.m_type = ConfigValues::IntType; + tmp.m_key = CFV_KEY_PARENT; + tmp.m_int = parent; + if(!put(tmp)){ + m_currentSection = parent; + return false; + } + + return true; +} + +bool +ConfigValuesFactory::closeSection(){ + ConfigValues::ConstIterator iter(* m_cfg); + iter.m_currentSection = m_currentSection; + const bool b = iter.closeSection(); + m_currentSection = iter.m_currentSection; + return b; +} + +bool +ConfigValuesFactory::put(const ConfigValues::Entry & entry){ + + if(m_freeKeys == 0 || + (entry.m_type == ConfigValues::StringType && m_freeData < sizeof(char *)) + || (entry.m_type == ConfigValues::Int64Type && m_freeData < 8 )){ + + DEBUG ndbout_c("m_freeKeys = %d, m_freeData = %d -> expand", + m_freeKeys, m_freeData); + + expand(31, 20); + } + + const Uint32 tmp = entry.m_key | m_currentSection; + const Uint32 sz = m_cfg->m_size; + Uint32 pos = hash(tmp, sz); + Uint32 count = 0; + Uint32 val = m_cfg->m_values[pos]; + + while((val & KP_MASK) != tmp && val != CFV_KEY_FREE && count < sz){ + pos = nextHash(tmp, sz, pos, ++count); + val = m_cfg->m_values[pos]; + } + + if((val & KP_MASK) == tmp){ + DEBUG ndbout_c("key %x already found at pos: %d", tmp, pos); + return false; + } + + if(count >= sz){ + pos = hash(tmp, sz); + count = 0; + Uint32 val = m_cfg->m_values[pos]; + + printf("key: %d, (key %% size): %d\n", entry.m_key, (entry.m_key % sz)); + printf("pos: %d", pos); + while((val & KP_MASK) != tmp && val != CFV_KEY_FREE && count < sz){ + pos = nextHash(tmp, sz, pos, ++count); + val = m_cfg->m_values[pos]; + printf(" %d", pos); + } + printf("\n"); + + abort(); + printf("Full\n"); + return false; + } + + assert(pos < (sz << 1)); + + Uint32 key = tmp; + key |= (entry.m_type << KP_TYPE_SHIFT); + m_cfg->m_values[pos] = key; + switch(entry.m_type){ + case ConfigValues::IntType: + case ConfigValues::SectionType: + m_cfg->m_values[pos+1] = entry.m_int; + m_freeKeys--; + DEBUG printf("Putting at: %d(%d) (loop = %d) key: %d value: %d\n", + pos, sz, count, + (key >> KP_KEYVAL_SHIFT) & KP_KEYVAL_MASK, + entry.m_int); + return true; + case ConfigValues::StringType:{ + Uint32 index = m_cfg->m_stringCount++; + m_cfg->m_values[pos+1] = index; + char ** ref = m_cfg->getString(index); + * ref = strdup(entry.m_string ? entry.m_string : ""); + m_freeKeys--; + m_freeData -= sizeof(char *); + DEBUG printf("Putting at: %d(%d) (loop = %d) key: %d value(%d): %s\n", + pos, sz, count, + (key >> KP_KEYVAL_SHIFT) & KP_KEYVAL_MASK, + index, + entry.m_string); + return true; + } + case ConfigValues::Int64Type:{ + Uint32 index = m_cfg->m_int64Count++; + m_cfg->m_values[pos+1] = index; + * m_cfg->get64(index) = entry.m_int64; + m_freeKeys--; + m_freeData -= 8; + DEBUG printf("Putting at: %d(%d) (loop = %d) key: %d value64(%d): %lld\n", + pos, sz, count, + (key >> KP_KEYVAL_SHIFT) & KP_KEYVAL_MASK, + index, + entry.m_int64); + return true; + } + case ConfigValues::InvalidType: + default: + return false; + } + return false; +} + +void +ConfigValuesFactory::put(const ConfigValues & cfg){ + + Uint32 curr = m_currentSection; + m_currentSection = 0; + + ConfigValues::Entry tmp; + for(Uint32 i = 0; i < 2 * cfg.m_size; i += 2){ + if(cfg.m_values[i] != CFV_KEY_FREE){ + tmp.m_key = cfg.m_values[i]; + cfg.getByPos(i, &tmp); + put(tmp); + } + } + + m_currentSection = curr; +} + +ConfigValues * +ConfigValuesFactory::extractCurrentSection(const ConfigValues::ConstIterator & cfg){ + ConfigValuesFactory * fac = new ConfigValuesFactory(20, 20); + Uint32 curr = cfg.m_currentSection; + + ConfigValues::Entry tmp; + for(Uint32 i = 0; i < 2 * cfg.m_cfg.m_size; i += 2){ + Uint32 keypart = cfg.m_cfg.m_values[i]; + const Uint32 sec = keypart & (KP_SECTION_MASK << KP_SECTION_SHIFT); + const Uint32 key = keypart & KP_KEYVAL_MASK; + if(sec == curr && key != CFV_KEY_PARENT){ + tmp.m_key = cfg.m_cfg.m_values[i]; + cfg.m_cfg.getByPos(i, &tmp); + tmp.m_key = key; + fac->put(tmp); + } + } + + ConfigValues * ret = fac->m_cfg; + delete fac; + return ret; +} + +ConfigValues * +ConfigValuesFactory::getConfigValues(){ + ConfigValues * ret = m_cfg; + m_cfg = create(10, 10); + return ret; +} + +static int +mod4(unsigned int i){ + int res = i + (4 - (i % 4)); + return res; +} + +Uint32 +ConfigValues::getPackedSize() const { + + Uint32 size = 0; + for(Uint32 i = 0; i < 2 * m_size; i += 2){ + Uint32 key = m_values[i]; + if(key != CFV_KEY_FREE){ + switch(::getTypeOf(key)){ + case IntType: + case SectionType: + size += 8; + break; + case Int64Type: + size += 12; + break; + case StringType: + size += 8; // key + len + size += mod4(strlen(* getString(m_values[i+1])) + 1); + break; + case InvalidType: + default: + abort(); + } + } + } + + return size + sizeof(Magic) + 4; // checksum also +} + +Uint32 +ConfigValues::pack(void * _dst, Uint32 _len) const { + Uint32 i; + char * dst = (char*)_dst; + memcpy(dst, Magic, sizeof(Magic)); dst += sizeof(Magic); + + for(i = 0; i < 2 * m_size; i += 2){ + Uint32 key = m_values[i]; + Uint32 val = m_values[i+1]; + if(key != CFV_KEY_FREE){ + switch(::getTypeOf(key)){ + case IntType: + case SectionType: + * (Uint32*)dst = htonl(key); dst += 4; + * (Uint32*)dst = htonl(val); dst += 4; + break; + case Int64Type:{ + Uint64 i64 = * get64(val); + Uint32 hi = (i64 >> 32); + Uint32 lo = (i64 & 0xFFFFFFFF); + * (Uint32*)dst = htonl(key); dst += 4; + * (Uint32*)dst = htonl(hi); dst += 4; + * (Uint32*)dst = htonl(lo); dst += 4; + } + break; + case StringType:{ + const char * str = * getString(val); + Uint32 len = strlen(str) + 1; + * (Uint32*)dst = htonl(key); dst += 4; + * (Uint32*)dst = htonl(len); dst += 4; + memcpy(dst, str, len); + memset(dst+len, 0, mod4(len) - len); + dst += mod4(len); + } + break; + case InvalidType: + default: + abort(); + } + } + } + + const Uint32 * sum = (Uint32*)_dst; + const Uint32 len = ((Uint32*)dst) - sum; + Uint32 chk = 0; + for(i = 0; i<len; i++){ + chk ^= htonl(sum[i]); + } + + * (Uint32*)dst = htonl(chk); dst += 4; + return 4 * (len + 1); +} + +bool +ConfigValuesFactory::unpack(const void * _src, Uint32 len){ + + if(len < sizeof(Magic) + 4){ + DEBUG abort(); + return false; + } + + if(memcmp(_src, Magic, sizeof(Magic)) != 0){ + DEBUG abort(); + return false; + } + + const char * src = (const char *)_src; + + { + Uint32 len32 = (len >> 2); + const Uint32 * tmp = (const Uint32*)_src; + Uint32 chk = 0; + for(Uint32 i = 0; (i+1)<len32; i++){ + chk ^= ntohl(tmp[i]); + } + + if(chk != ntohl(tmp[len32-1])){ + DEBUG abort(); + return false; + } + } + + const char * end = src + len - 4; + src += sizeof(Magic); + + ConfigValues::Entry entry; + while(end - src > 4){ + Uint32 tmp = ntohl(* (const Uint32 *)src); src += 4; + entry.m_key = tmp & KP_MASK; + entry.m_type = ::getTypeOf(tmp); + switch(entry.m_type){ + case ConfigValues::IntType: + case ConfigValues::SectionType: + entry.m_int = ntohl(* (const Uint32 *)src); src += 4; + break; + case ConfigValues::Int64Type:{ + Uint64 hi = ntohl(* (const Uint32 *)src); src += 4; + Uint64 lo = ntohl(* (const Uint32 *)src); src += 4; + entry.m_int64 = (hi <<32) | lo; + } + break; + case ConfigValues::StringType:{ + Uint32 s_len = ntohl(* (const Uint32 *)src); src += 4; + size_t s_len2 = strlen((const char*)src); + if(s_len2 + 1 != s_len){ + DEBUG abort(); + return false; + } + + entry.m_string = (const char*)src; src+= mod4(s_len); + } + break; + case ConfigValues::InvalidType: + default: + DEBUG abort(); + return false; + } + if(!put(entry)){ + DEBUG abort(); + return false; + } + } + if(src != end){ + DEBUG abort(); + return false; + } + return true; +} + +#ifdef __TEST_CV_HASH_HPP + +int +main(void){ + srand(time(0)); + for(int t = 0; t<100; t++){ + const size_t len = directory(rand() % 1000); + + printf("size = %d\n", len); + unsigned * buf = new unsigned[len]; + for(size_t key = 0; key<len; key++){ + Uint32 p = hash(key, len); + for(size_t j = 0; j<len; j++){ + buf[j] = p; + p = nextHash(key, len, p, j+1); + } + + for(size_t j = 0; j<len; j++){ + Uint32 pos = buf[j]; + int unique = 0; + for(size_t k = j + 1; k<len; k++){ + if(pos == buf[k]){ + if(unique > 0) + printf("size=%d key=%d pos(%d)=%d buf[%d]=%d\n", len, key, j, pos, k, buf[k]); + unique ++; + } + } + if(unique > 1){ + printf("key = %d size = %d not uniqe!!\n", key, len); + for(size_t k = 0; k<len; k++){ + printf("%d ", buf[k]); + } + printf("\n"); + } + } + } + delete[] buf; + } + return 0; +} + +#endif diff --git a/storage/ndb/src/common/util/File.cpp b/storage/ndb/src/common/util/File.cpp new file mode 100644 index 00000000000..937b8c0fa59 --- /dev/null +++ b/storage/ndb/src/common/util/File.cpp @@ -0,0 +1,205 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <ndb_global.h> + +#include <File.hpp> + +#include <NdbOut.hpp> +#include <my_dir.h> + +// +// PUBLIC +// + +bool +File_class::exists(const char* aFileName) +{ + bool rc = true; +#ifdef USE_MY_STAT_STRUCT + struct my_stat stmp; +#else + struct stat stmp; +#endif + if (my_stat(aFileName, &stmp, MYF(0)) != 0) + { + rc = false; + } + + /* + File f; + if (!f.open(aFileName, "r")) + { + rc = (errno == ENOENT ? false : true); + } + else + { + f.close(); + } + */ + return rc; +} + +long +File_class::size(FILE* f) +{ + long cur_pos = 0, length = 0; + + cur_pos = ::ftell(f); + ::fseek(f, 0, SEEK_END); + length = ::ftell(f); + ::fseek(f, cur_pos, SEEK_SET); // restore original position + + return length; +} + +bool +File_class::rename(const char* currFileName, const char* newFileName) +{ + return ::rename(currFileName, newFileName) == 0 ? true : false; +} +bool +File_class::remove(const char* aFileName) +{ + return ::remove(aFileName) == 0 ? true : false; +} + +File_class::File_class() : + m_file(NULL), + m_fileMode("r") +{ +} + +File_class::File_class(const char* aFileName, const char* mode) : + m_file(NULL), + m_fileMode(mode) +{ + BaseString::snprintf(m_fileName, MAX_FILE_NAME_SIZE, aFileName); +} + +bool +File_class::open() +{ + return open(m_fileName, m_fileMode); +} + +bool +File_class::open(const char* aFileName, const char* mode) +{ + if(m_fileName != aFileName){ + /** + * Only copy if it's not the same string + */ + BaseString::snprintf(m_fileName, MAX_FILE_NAME_SIZE, aFileName); + } + m_fileMode = mode; + bool rc = true; + if ((m_file = ::fopen(m_fileName, m_fileMode))== NULL) + { + rc = false; + } + + return rc; +} +File_class::~File_class() +{ + close(); +} + +bool +File_class::remove() +{ + // Close the file first! + close(); + return File_class::remove(m_fileName); +} + +bool +File_class::close() +{ + bool rc = true; + if (m_file != NULL) + { + ::fflush(m_file); + rc = (::fclose(m_file) == 0 ? true : false); + m_file = NULL; // Try again? + } + + return rc; +} + +int +File_class::read(void* buf, size_t itemSize, size_t nitems) const +{ + return ::fread(buf, itemSize, nitems, m_file); +} + +int +File_class::readChar(char* buf, long start, long length) const +{ + return ::fread((void*)&buf[start], 1, length, m_file); +} + +int +File_class::readChar(char* buf) +{ + return readChar(buf, 0, strlen(buf)); +} + +int +File_class::write(const void* buf, size_t size, size_t nitems) +{ + return ::fwrite(buf, size, nitems, m_file); +} + +int +File_class::writeChar(const char* buf, long start, long length) +{ + return ::fwrite((const void*)&buf[start], sizeof(char), length, m_file); +} + +int +File_class::writeChar(const char* buf) +{ + return writeChar(buf, 0, ::strlen(buf)); +} + +long +File_class::size() const +{ + return File_class::size(m_file); +} + +const char* +File_class::getName() const +{ + return m_fileName; +} + +int +File_class::flush() const +{ +#if defined NDB_OSE || defined NDB_SOFTOSE + ::fflush(m_file); + return ::fsync(::fileno(m_file)); +#else + return 0; +#endif +} + +// +// PRIVATE +// diff --git a/storage/ndb/src/common/util/InputStream.cpp b/storage/ndb/src/common/util/InputStream.cpp new file mode 100644 index 00000000000..410e9a70e9c --- /dev/null +++ b/storage/ndb/src/common/util/InputStream.cpp @@ -0,0 +1,61 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +#include <ndb_global.h> + +#include "InputStream.hpp" +#include <socket_io.h> + +FileInputStream Stdin(stdin); + +FileInputStream::FileInputStream(FILE * file) + : f(file) { +} + +char* +FileInputStream::gets(char * buf, int bufLen){ + if(!feof(f)){ + return fgets(buf, bufLen, f); + } + return 0; +} + +SocketInputStream::SocketInputStream(NDB_SOCKET_TYPE socket, + unsigned readTimeout) + : m_socket(socket) { + m_timeout = readTimeout; +} + +char* +SocketInputStream::gets(char * buf, int bufLen) { + buf[0] = 77; + assert(bufLen >= 2); + int res = readln_socket(m_socket, m_timeout, buf, bufLen - 1); + if(res == -1) + return 0; + if(res == 0 && buf[0] == 77){ // select return 0 + buf[0] = 0; + } else if(res == 0 && buf[0] == 0){ // only newline + buf[0] = '\n'; + buf[1] = 0; + } else { + int len = strlen(buf); + buf[len + 1] = '\0'; + buf[len] = '\n'; + } + return buf; +} diff --git a/storage/ndb/src/common/util/Makefile.am b/storage/ndb/src/common/util/Makefile.am new file mode 100644 index 00000000000..2719d14ee92 --- /dev/null +++ b/storage/ndb/src/common/util/Makefile.am @@ -0,0 +1,49 @@ + +noinst_LTLIBRARIES = libgeneral.la + +libgeneral_la_SOURCES = \ + File.cpp md5_hash.cpp Properties.cpp socket_io.cpp \ + SimpleProperties.cpp Parser.cpp InputStream.cpp \ + SocketServer.cpp SocketClient.cpp SocketAuthenticator.cpp\ + OutputStream.cpp NdbOut.cpp BaseString.cpp Base64.cpp \ + NdbSqlUtil.cpp new.cpp \ + uucode.c random.c version.c \ + strdup.c \ + ConfigValues.cpp ndb_init.c basestring_vsnprintf.c \ + Bitmask.cpp + +EXTRA_PROGRAMS = testBitmask +testBitmask_SOURCES = testBitmask.cpp +testBitmask_LDFLAGS = @ndb_bin_am_ldflags@ \ + $(top_builddir)/ndb/src/libndbclient.la \ + $(top_builddir)/dbug/libdbug.a \ + $(top_builddir)/mysys/libmysys.a \ + $(top_builddir)/strings/libmystrings.a + +testBitmask.cpp : Bitmask.cpp + rm -f testBitmask.cpp + @LN_CP_F@ Bitmask.cpp testBitmask.cpp + +testBitmask.o: $(testBitmask_SOURCES) + $(CXXCOMPILE) -c $(INCLUDES) -D__TEST_BITMASK__ $< + + +include $(top_srcdir)/ndb/config/common.mk.am +include $(top_srcdir)/ndb/config/type_util.mk.am + +# Don't update the files from bitkeeper +%::SCCS/s.% + +windoze-dsp: libgeneral.dsp + +libgeneral.dsp: Makefile \ + $(top_srcdir)/ndb/config/win-lib.am \ + $(top_srcdir)/ndb/config/win-name \ + $(top_srcdir)/ndb/config/win-includes \ + $(top_srcdir)/ndb/config/win-sources \ + $(top_srcdir)/ndb/config/win-libraries + cat $(top_srcdir)/ndb/config/win-lib.am > $@ + @$(top_srcdir)/ndb/config/win-name $@ $(noinst_LTLIBRARIES) + @$(top_srcdir)/ndb/config/win-includes $@ $(INCLUDES) + @$(top_srcdir)/ndb/config/win-sources $@ $(libgeneral_la_SOURCES) + @$(top_srcdir)/ndb/config/win-libraries $@ LIB $(LDADD) diff --git a/storage/ndb/src/common/util/NdbErrHnd.cpp b/storage/ndb/src/common/util/NdbErrHnd.cpp new file mode 100644 index 00000000000..38a67f29853 --- /dev/null +++ b/storage/ndb/src/common/util/NdbErrHnd.cpp @@ -0,0 +1,492 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +#if defined NDB_OSE || defined NDB_SOFTOSE + +#include <NdbOut.hpp> +#include <ndb_types.h> + +#include "ose.h" +#include "ose_err.h" +#include "osetypes.h" + + +#define BUFSIZE 100 + +typedef struct { + char header1[BUFSIZE]; + char header2[BUFSIZE]; + char error_code_line[BUFSIZE]; + char subcode_line[BUFSIZE]; + char product_line[BUFSIZE]; + char header_file_line[BUFSIZE]; + char extra_line[BUFSIZE]; + char user_called_line[BUFSIZE]; + char current_process_id_line[BUFSIZE]; + char current_process_name_line[BUFSIZE]; + char file_line[BUFSIZE]; + char line_line[BUFSIZE]; + char err_hnd_file[BUFSIZE]; +} Error_message; + +char assert_line[BUFSIZE]; +char unknown_signal_line[BUFSIZE]; +char signal_number_line[BUFSIZE]; +char sender_line[BUFSIZE]; +char receiver_line[BUFSIZE]; + +extern "C" OSBOOLEAN ndb_err_hnd(bool user_called, + Uint32 error_code, + Uint32 extra) +{ + static Error_message error_message; + bool error_handled; + Uint32 subcode; + + char* subcode_mnemonic; + char* product_name; + char* file_name; + + /*The subcode (bit 16 - 30) is extracted from error_code */ + subcode = (error_code & 0x7fff0000) >> 16; + + if (user_called) { + switch (subcode) { + case 0x0050 : + subcode_mnemonic= "OSE_PRH_PLS"; + product_name= "Program Loader"; + file_name = "prherr.h"; + break; + case 0x0051 : + subcode_mnemonic = "OSE_PRH_START_PRH"; + product_name= "start_prh"; + file_name= " start_prh.c"; + break; + case 0x0052 : + subcode_mnemonic= "OSE_PRH_ASF"; + product_name= "Archive Server"; + file_name = "prherr.h"; + break; + case 0x0058 : + case 0x4058 : + case 0x3fff : + case 0x8058 : + subcode_mnemonic= "OSE_MMS_EBASE"; + product_name= "MMS"; + file_name= "mms_err.h"; + break; + /*Link Handler G3***************************************/ + case 0x0060 : + case 0x8060 : + subcode_mnemonic= "OSE_GLH_EBASE"; + product_name= "General Link Handler"; + file_name= "glherr.h"; + break; + case 0x0064 : + case 0x8064 : + subcode_mnemonic= "OSE_GPL_EBASE"; + product_name= "General Protocol Link Handler"; + file_name= "gplerr.h"; + break; + case 0x0066 : + case 0x8066 : + subcode_mnemonic= "OSE_UDPPDR_EBASE"; + product_name= "UDP driver for GPL"; + file_name= "udppdrerr.h"; + break; + case 0x0067 : + case 0x8067 : + subcode_mnemonic= "OSE_SERPDR_EBASE"; + product_name= "Serial driver for GPL"; + file_name= "serpdrerr.h"; + break; + case 0x0068 : + case 0x8068 : + subcode_mnemonic= "OSE_ETHPDR_EBASE"; + product_name= "Ethernet driver for GPL"; + file_name= "ethpdrerr.h"; + break; + /*Link handler G4***************************************/ + case 0x0061 : + subcode_mnemonic= "OSE_OTL_EBASE"; + product_name= "OSE Transport Layer"; + file_name= "otlerr.h"; + break; + case 0x0062 : + subcode_mnemonic= "OSE_LALUDP_EBASE"; + product_name= "Link Adaption Layer for UDP"; + file_name= "header file unknown"; + break; + /*Internet Utilities************************************/ + case 0x0069 : + subcode_mnemonic= "OSE_TFTPD"; + product_name= "TFTP server"; + file_name= "inetutilerr.h"; + break; + case 0x006a : + subcode_mnemonic= "OSE_TELUDPD"; + product_name= "TELNET/UDP server"; + file_name= "inetutilerr.h"; + break; + case 0x006b : + subcode_mnemonic= "OSE_FTPD"; + product_name= "FTP server"; + file_name= "inetutilerr.h"; + break; + case 0x006c : + subcode_mnemonic= "OSE_TELNETD"; + product_name= "TELNET server"; + file_name= "inetutilerr.h"; + break; + case 0x006d : + subcode_mnemonic= "OSE_SURFER"; + product_name= "OSE System Surfer"; + file_name= "inetutilerr.h"; + break; + case 0x006e : + subcode_mnemonic= "OSE_BOOTP"; + product_name= "BOOTP client"; + file_name= "inetutilerr.h"; + break; + case 0x006f : + switch((error_code & 0x0000f000)){ + case 0x00000000 : + subcode_mnemonic= "OSE_RES"; + product_name= "DNS resolver"; + file_name= "inetutilerr.h"; + break; + case 0x00001000 : + subcode_mnemonic= "OSE_DHCPC"; + product_name= "DHCP client"; + file_name= "inetutilerr.h"; + break; + case 0x00002000 : + subcode_mnemonic= "OSE_FTP"; + product_name= "FTP client"; + file_name= "inetutilerr.h"; + break; + default : + subcode_mnemonic= "Unknown error"; + product_name= "unknown product"; + file_name = "header file unknown"; + break; + } + break; + case 0x00c2 : + subcode_mnemonic= "OSE_DNS"; + product_name= "DNS server"; + file_name= "dns_err.h"; + break; + /*INET**************************/ + case 0x0070 : + subcode_mnemonic= "INET_ERRBASE"; + product_name= "Internet Protocols (INET)"; + file_name= "ineterr.h"; + break; + case 0x0071 : + subcode_mnemonic= "WEBS_ERRBASE"; + product_name= "Web Server (WEBS)"; + file_name= "webserr.h"; + break; + case 0x0072 : + subcode_mnemonic= "SNMP"; + product_name= "SNMP"; + file_name= "header file unknown"; + break; + case 0x0073 : + subcode_mnemonic= "STP_BRIDGE"; + product_name= "STP bridge"; + file_name= "header file unknown"; + break; + case 0x0200 : + case 0x0201 : + case 0x0202 : + case 0x0203 : + case 0x0204 : + case 0x0205 : + case 0x0206 : + case 0x0207 : + case 0x0208 : + case 0x0209 : + case 0x020a : + case 0x020b : + case 0x020c : + case 0x020d : + case 0x020e : + case 0x020f : + subcode_mnemonic = "INETINIT_ERR_BASE"; + product_name = "INET"; + file_name = "startinet.c"; + break; + /*Miscellanous******************************************/ + case 0x0082 : + subcode_mnemonic= "OSE_HEAP_EBASE"; + product_name= "Heap Manager"; + file_name= "heap_err.h"; + break; + case 0x0088 : + subcode_mnemonic= "OSE_BSP"; + product_name= "Board Support Package"; + file_name= "bsperr.h"; + break; + case 0x008a : + subcode_mnemonic= "OSE_TOSV_EBASE"; + product_name= "Time Out Server"; + file_name= "tosverr.h"; + break; + case 0x008b : + subcode_mnemonic= "OSE_RTC_EBASE"; + product_name= "Real Time Clock"; + file_name= "rtcerr.h"; + break; + case 0x008d : + case 0x808d : + subcode_mnemonic= "OSENS_ERR_BASE"; + product_name= "Name Server"; + file_name= "osens_err.h"; + break; + case 0x008e : + subcode_mnemonic= "PMD_ERR_BASE"; + product_name= "Post Mortem Dump"; + file_name= "pmderr.h"; + break; + /*Embedded File System***********************************/ + case 0x0090 : + subcode_mnemonic= "OSE_EFS_COMMON"; + product_name= "EFS common"; + file_name= "efs_err.h"; + break; + case 0x0091 : + subcode_mnemonic= "OSE_EFS_FLIB"; + product_name= "EFS function library"; + file_name= "efs_err.h"; + break; + case 0x0092 : + subcode_mnemonic= "OSE_EFS_SERDD"; + product_name= "EFS serdd"; + file_name= "efs_err.h"; + break; + case 0x0093 : + subcode_mnemonic= "OSE_EFS_SHELL"; + product_name= "OSE shell"; + file_name= "efs_err.h"; + break; + case 0x0094 : + subcode_mnemonic= "OSE_EFS_STARTEFS"; + product_name= "EFS startefs.c"; + file_name= "efs_err.h"; + break; + /*Debugger related***************************************/ + case 0x00a0 : + subcode_mnemonic= "DBGSERVER_ERR_BASE"; + product_name= "Debug server for Illuminator"; + file_name= "degservererr.h"; + break; + case 0x00b2 : + subcode_mnemonic= "OSE_MDM"; + product_name= "Multi INDRT monitor"; + file_name= "header file unknown"; + break; + /*Miscellanous*******************************************/ + case 0x00c0 : + subcode_mnemonic= "OSE_POTS_EBASE"; + product_name= "POTS tutorial example"; + file_name= "pots_err.h"; + break; + case 0x00c1 : + subcode_mnemonic= "OSE_PTH_ECODE_BASE"; + product_name= "Pthreads"; + file_name= "pthread_err.h"; + break; + case 0x00c3 : + subcode_mnemonic= "OSE_NTP_EBASE"; + product_name= "OSE NTP/SNTP"; + file_name= "ntp_err.h"; + break; + case 0x00c4 : + subcode_mnemonic= "TRILLIUM_BASE"; + product_name= "Trillium OSE port"; + file_name= "sk_ss.c"; + break; + case 0x00c5 : + subcode_mnemonic= "OSE_OSECPP_EBASE"; + product_name= "C++ Support with libosecpp.a"; + file_name= "cpp_err.h"; + break; + case 0x00c6 : + subcode_mnemonic= "OSE_RIP_ERR_BASE"; + product_name= "OSE RIP"; + file_name= "oserip.h"; + break; + /*Unknown error_code*************************************/ + default : + subcode_mnemonic= "Unknown error"; + product_name= "unknown product"; + file_name = "header file unknown"; + break; + } + } else { + /* user_called = 0, i.e. reported by the kernel */ + subcode_mnemonic= "OSE_KRN"; + product_name= "Kernel"; + file_name = "ose_err.h"; + } + + BaseString::snprintf(error_message.header1, + BUFSIZE, + "This is the OSE Example System Error handler\r\n"); + + BaseString::snprintf(error_message.err_hnd_file, + BUFSIZE, + "located in: " __FILE__ "\r\n"); + + BaseString::snprintf(error_message.header2, + BUFSIZE, + "An Error has been reported:\r\n"); + + if (user_called == (OSBOOLEAN) 0 ) { + BaseString::snprintf(error_message.user_called_line, + BUFSIZE, + "user_called: 0x%x (Error detected by the kernel)\r\n", + user_called); + } + else { + BaseString::snprintf(error_message.user_called_line, + BUFSIZE, + "user_called: 0x%x (Error detected by an application)\r\n", + user_called); + } + + BaseString::snprintf(error_message.error_code_line, + BUFSIZE, + "error code: 0x%08x\r\n", + error_code); + + BaseString::snprintf(error_message.subcode_line, + BUFSIZE, + " subcode: %s (0x%08x)\r\n", + subcode_mnemonic, + ( subcode << 16)); + + BaseString::snprintf(error_message.product_line, + BUFSIZE, + " product: %s\r\n", + product_name); + + BaseString::snprintf(error_message.header_file_line, + BUFSIZE, + " header file: %s\r\n", + file_name); + + BaseString::snprintf(error_message.extra_line, + BUFSIZE, + "extra: 0x%08x\r\n", + extra); + + if (error_code != OSE_ENO_KERN_SPACE || user_called){ + struct OS_pcb *pcb = get_pcb(current_process()); + const char *process_name = &pcb->strings[pcb->name]; + + BaseString::snprintf(error_message.current_process_id_line, + BUFSIZE, + "Current Process: 0x%08x\r\n", + current_process()); + + BaseString::snprintf(error_message.current_process_name_line, + BUFSIZE, + "Process Name: %s\r\n", + process_name); + + BaseString::snprintf(error_message.file_line, + BUFSIZE, + "File: %s\r\n", + &pcb->strings[pcb->file]); + + BaseString::snprintf(error_message.line_line, + BUFSIZE, + "Line: %d\r\n", + pcb->line); + + free_buf((union SIGNAL **)&pcb); + } + + if ( !(((error_code & OSE_EFATAL_MASK) != 0) && (user_called == 0))){ + /* If the error is reported by the kernel and the fatal flag is set, + * dbgprintf can't be trusted */ + ndbout << error_message.header1; + ndbout << error_message.err_hnd_file; + ndbout << error_message.header2; + ndbout << error_message.user_called_line; + ndbout << error_message.error_code_line; + ndbout << error_message.subcode_line; + ndbout << error_message.product_line; + ndbout << error_message.header_file_line; + ndbout << error_message.extra_line; + ndbout << error_message.current_process_id_line; + ndbout << error_message.current_process_name_line; + ndbout << error_message.file_line; + ndbout << error_message.line_line; + ndbout << endl; + } + + if(user_called){ + switch (error_code) { + /* Check for assertion failure (see oseassert.h and assert.c). */ + case (OSERRCODE) 0xffffffff: + { + if(extra != 0){ + char *expr = ((char **)extra)[0]; + char *file = ((char **)extra)[1]; + unsigned line = ((unsigned *)extra)[2]; + BaseString::snprintf(assert_line, BUFSIZE, "Assertion Failed: %s:%u: %s\r\n", file, line, expr); + ndbout << assert_line; + } + } + /* Check for unknown signal */ + case (OSERRCODE) 0xfffffffe: + { + union SIGNAL *sig = (union SIGNAL *)extra; + SIGSELECT signo = *(SIGSELECT*)sig; + PROCESS rcv_ = current_process(); + PROCESS snd_ = sender(&sig); + struct OS_pcb *rcv = get_pcb(rcv_); + const char *rcv_name = &rcv->strings[rcv->name]; + struct OS_pcb *snd = get_pcb(snd_); + const char *snd_name = &snd->strings[snd->name]; + BaseString::snprintf(unknown_signal_line, BUFSIZE, + "Unknown Signal Received\r\n"); + BaseString::snprintf(unknown_signal_line, BUFSIZE, + "Signal Number: 0x%08lx\r\n", signo); + BaseString::snprintf(unknown_signal_line, BUFSIZE, + "Sending Process: 0x%08lx (%s))\r\n", snd_, snd_name); + BaseString::snprintf(unknown_signal_line, BUFSIZE, + "Receiving Process: 0x%08lx (%s))\r\n", rcv_, rcv_name); + free_buf((union SIGNAL **)&rcv); + free_buf((union SIGNAL **)&snd); } + ndbout << unknown_signal_line; + ndbout << signal_number_line; + ndbout << sender_line; + ndbout << receiver_line; + } /* switch */ + } /* if */ + + /* Zero means the error has not been fixed by the error handler. */ + error_handled = 0; + return error_handled; +} + +#endif diff --git a/storage/ndb/src/common/util/NdbOut.cpp b/storage/ndb/src/common/util/NdbOut.cpp new file mode 100644 index 00000000000..e20119a7987 --- /dev/null +++ b/storage/ndb/src/common/util/NdbOut.cpp @@ -0,0 +1,173 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <ndb_global.h> + +#include <NdbOut.hpp> +#include <OutputStream.hpp> + +static FileOutputStream ndbouts_fileoutputstream(stdout); +NdbOut ndbout(ndbouts_fileoutputstream); + +static const char * fms[] = { + "%d", "0x%02x", // Int8 + "%u", "0x%02x", // Uint8 + "%d", "0x%04x", // Int16 + "%u", "0x%04x", // Uint16 + "%d", "0x%08x", // Int32 + "%u", "0x%08x", // Uint32 + "%lld", "0x%016llx", // Int64 + "%llu", "0x%016llx" // Uint64 + "%llu", "0x%016llx" // UintPtr +}; + +NdbOut& +NdbOut::operator<<(Int8 v) { m_out->print(fms[0+isHex],(int)v); return *this;} +NdbOut& +NdbOut::operator<<(Uint8 v) { m_out->print(fms[2+isHex],(int)v); return *this;} +NdbOut& +NdbOut::operator<<(Int16 v) { m_out->print(fms[4+isHex],(int)v); return *this;} +NdbOut& +NdbOut::operator<<(Uint16 v) { m_out->print(fms[6+isHex],(int)v); return *this;} +NdbOut& +NdbOut::operator<<(Int32 v) { m_out->print(fms[8+isHex], v); return *this;} +NdbOut& +NdbOut::operator<<(Uint32 v) { m_out->print(fms[10+isHex], v); return *this;} +NdbOut& +NdbOut::operator<<(Int64 v) { m_out->print(fms[12+isHex], v); return *this;} +NdbOut& +NdbOut::operator<<(Uint64 v) { m_out->print(fms[14+isHex], v); return *this;} +NdbOut& +NdbOut::operator<<(unsigned long int v) { return *this << (Uint64) v; } + +NdbOut& +NdbOut::operator<<(const char* val){ m_out->print("%s", val ? val : "(null)"); return * this; } +NdbOut& +NdbOut::operator<<(const void* val){ m_out->print("%p", val); return * this; } +NdbOut& +NdbOut::operator<<(BaseString &val){ return *this << val.c_str(); } + +NdbOut& +NdbOut::operator<<(float val){ m_out->print("%f", (double)val); return * this;} +NdbOut& +NdbOut::operator<<(double val){ m_out->print("%f", val); return * this; } + +NdbOut& NdbOut::endline() +{ + isHex = 0; // Reset hex to normal, if user forgot this + m_out->println(""); + m_out->flush(); + return *this; +} + +NdbOut& NdbOut::flushline() +{ + m_out->flush(); + return *this; +} + +NdbOut& NdbOut::setHexFormat(int _format) +{ + isHex = (_format == 0 ? 0 : 1); + return *this; +} + +NdbOut::NdbOut(OutputStream & out) + : m_out(& out) +{ + isHex = 0; +} + +NdbOut::~NdbOut() +{ +} + +void +NdbOut::print(const char * fmt, ...){ + va_list ap; + char buf[1000]; + + va_start(ap, fmt); + if (fmt != 0) + BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap); + ndbout << buf; + va_end(ap); +} + +void +NdbOut::println(const char * fmt, ...){ + va_list ap; + char buf[1000]; + + va_start(ap, fmt); + if (fmt != 0) + BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap); + ndbout << buf << endl; + va_end(ap); +} + +extern "C" +void +ndbout_c(const char * fmt, ...){ + va_list ap; + char buf[1000]; + + va_start(ap, fmt); + if (fmt != 0) + BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap); + ndbout << buf << endl; + va_end(ap); +} + +FilteredNdbOut::FilteredNdbOut(OutputStream & out, + int threshold, int level) + : NdbOut(out) { + m_level = level; + m_threshold = threshold; + m_org = &out; + m_null = new NullOutputStream(); + setLevel(level); +} + +FilteredNdbOut::~FilteredNdbOut(){ + delete m_null; +} + +void +FilteredNdbOut::setLevel(int i){ + m_level = i; + if(m_level >= m_threshold){ + m_out = m_org; + } else { + m_out = m_null; + } +} + +void +FilteredNdbOut::setThreshold(int i){ + m_threshold = i; + setLevel(m_level); +} + +int +FilteredNdbOut::getLevel() const { + return m_level; +} +int +FilteredNdbOut::getThreshold() const { + return m_threshold; +} + diff --git a/storage/ndb/src/common/util/NdbSqlUtil.cpp b/storage/ndb/src/common/util/NdbSqlUtil.cpp new file mode 100644 index 00000000000..09e150dbacf --- /dev/null +++ b/storage/ndb/src/common/util/NdbSqlUtil.cpp @@ -0,0 +1,1007 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <NdbSqlUtil.hpp> +#include <NdbOut.hpp> +#include <my_sys.h> + +/* + * Data types. The entries must be in the numerical order. + */ + +const NdbSqlUtil::Type +NdbSqlUtil::m_typeList[] = { + { // 0 + Type::Undefined, + NULL, + NULL + }, + { // 1 + Type::Tinyint, + cmpTinyint, + NULL + }, + { // 2 + Type::Tinyunsigned, + cmpTinyunsigned, + NULL + }, + { // 3 + Type::Smallint, + cmpSmallint, + NULL + }, + { // 4 + Type::Smallunsigned, + cmpSmallunsigned, + NULL + }, + { // 5 + Type::Mediumint, + cmpMediumint, + NULL + }, + { // 6 + Type::Mediumunsigned, + cmpMediumunsigned, + NULL + }, + { // 7 + Type::Int, + cmpInt, + NULL + }, + { // 8 + Type::Unsigned, + cmpUnsigned, + NULL + }, + { // 9 + Type::Bigint, + cmpBigint, + NULL + }, + { // 10 + Type::Bigunsigned, + cmpBigunsigned, + NULL + }, + { // 11 + Type::Float, + cmpFloat, + NULL + }, + { // 12 + Type::Double, + cmpDouble, + NULL + }, + { // 13 + Type::Olddecimal, + cmpOlddecimal, + NULL + }, + { // 14 + Type::Char, + cmpChar, + likeChar + }, + { // 15 + Type::Varchar, + cmpVarchar, + likeVarchar + }, + { // 16 + Type::Binary, + cmpBinary, + likeBinary + }, + { // 17 + Type::Varbinary, + cmpVarbinary, + likeVarbinary + }, + { // 18 + Type::Datetime, + cmpDatetime, + NULL + }, + { // 19 + Type::Date, + cmpDate, + NULL + }, + { // 20 + Type::Blob, + NULL, + NULL + }, + { // 21 + Type::Text, + NULL, + NULL + }, + { // 22 + Type::Bit, + NULL, + NULL + }, + { // 23 + Type::Longvarchar, + cmpLongvarchar, + likeLongvarchar + }, + { // 24 + Type::Longvarbinary, + cmpLongvarbinary, + likeLongvarbinary + }, + { // 25 + Type::Time, + cmpTime, + NULL + }, + { // 26 + Type::Year, + cmpYear, + NULL + }, + { // 27 + Type::Timestamp, + cmpTimestamp, + NULL + }, + { // 28 + Type::Olddecimalunsigned, + cmpOlddecimalunsigned, + NULL + }, + { // 29 + Type::Decimal, + cmpDecimal, + NULL + }, + { // 30 + Type::Decimalunsigned, + cmpDecimalunsigned, + NULL + } +}; + +const NdbSqlUtil::Type& +NdbSqlUtil::getType(Uint32 typeId) +{ + if (typeId < sizeof(m_typeList) / sizeof(m_typeList[0]) && + m_typeList[typeId].m_typeId != Type::Undefined) { + return m_typeList[typeId]; + } + return m_typeList[Type::Undefined]; +} + +const NdbSqlUtil::Type& +NdbSqlUtil::getTypeBinary(Uint32 typeId) +{ + switch (typeId) { + case Type::Char: + case Type::Varchar: + case Type::Binary: + case Type::Varbinary: + case Type::Longvarchar: + case Type::Longvarbinary: + typeId = Type::Binary; + break; + case Type::Text: + typeId = Type::Blob; + break; + default: + break; + } + return getType(typeId); +} + +/* + * Comparison functions. + */ + +int +NdbSqlUtil::cmpTinyint(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +{ + if (n2 >= sizeof(Int8)) { + Int8 v1, v2; + memcpy(&v1, p1, sizeof(Int8)); + memcpy(&v2, p2, sizeof(Int8)); + if (v1 < v2) + return -1; + if (v1 > v2) + return +1; + return 0; + } + assert(! full); + return CmpUnknown; +} + +int +NdbSqlUtil::cmpTinyunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +{ + if (n2 >= sizeof(Uint8)) { + Uint8 v1, v2; + memcpy(&v1, p1, sizeof(Uint8)); + memcpy(&v2, p2, sizeof(Uint8)); + if (v1 < v2) + return -1; + if (v1 > v2) + return +1; + return 0; + } + assert(! full); + return CmpUnknown; +} + +int +NdbSqlUtil::cmpSmallint(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +{ + if (n2 >= sizeof(Int16)) { + Int16 v1, v2; + memcpy(&v1, p1, sizeof(Int16)); + memcpy(&v2, p2, sizeof(Int16)); + if (v1 < v2) + return -1; + if (v1 > v2) + return +1; + return 0; + } + assert(! full); + return CmpUnknown; +} + +int +NdbSqlUtil::cmpSmallunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +{ + if (n2 >= sizeof(Uint16)) { + Uint16 v1, v2; + memcpy(&v1, p1, sizeof(Uint16)); + memcpy(&v2, p2, sizeof(Uint16)); + if (v1 < v2) + return -1; + if (v1 > v2) + return +1; + return 0; + } + assert(! full); + return CmpUnknown; +} + +int +NdbSqlUtil::cmpMediumint(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +{ + if (n2 >= 3) { + Int32 v1, v2; + v1 = sint3korr((const uchar*)p1); + v2 = sint3korr((const uchar*)p2); + if (v1 < v2) + return -1; + if (v1 > v2) + return +1; + return 0; + } + assert(! full); + return CmpUnknown; +} + +int +NdbSqlUtil::cmpMediumunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +{ + if (n2 >= 3) { + Uint32 v1, v2; + v1 = uint3korr((const uchar*)p1); + v2 = uint3korr((const uchar*)p2); + if (v1 < v2) + return -1; + if (v1 > v2) + return +1; + return 0; + } + assert(! full); + return CmpUnknown; +} + +int +NdbSqlUtil::cmpInt(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +{ + if (n2 >= sizeof(Int32)) { + Int32 v1, v2; + memcpy(&v1, p1, sizeof(Int32)); + memcpy(&v2, p2, sizeof(Int32)); + if (v1 < v2) + return -1; + if (v1 > v2) + return +1; + return 0; + } + assert(! full); + return CmpUnknown; +} + +int +NdbSqlUtil::cmpUnsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +{ + if (n2 >= sizeof(Uint32)) { + Uint32 v1, v2; + memcpy(&v1, p1, sizeof(Uint32)); + memcpy(&v2, p2, sizeof(Uint32)); + if (v1 < v2) + return -1; + if (v1 > v2) + return +1; + return 0; + } + assert(! full); + return CmpUnknown; +} + +int +NdbSqlUtil::cmpBigint(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +{ + if (n2 >= sizeof(Int64)) { + Int64 v1, v2; + memcpy(&v1, p1, sizeof(Int64)); + memcpy(&v2, p2, sizeof(Int64)); + if (v1 < v2) + return -1; + if (v1 > v2) + return +1; + return 0; + } + assert(! full); + return CmpUnknown; +} + +int +NdbSqlUtil::cmpBigunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +{ + if (n2 >= sizeof(Uint64)) { + Uint64 v1, v2; + memcpy(&v1, p1, sizeof(Uint64)); + memcpy(&v2, p2, sizeof(Uint64)); + if (v1 < v2) + return -1; + if (v1 > v2) + return +1; + return 0; + } + assert(! full); + return CmpUnknown; +} + +int +NdbSqlUtil::cmpFloat(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +{ + if (n2 >= sizeof(float)) { + float v1, v2; + memcpy(&v1, p1, sizeof(float)); + memcpy(&v2, p2, sizeof(float)); + if (v1 < v2) + return -1; + if (v1 > v2) + return +1; + return 0; + } + assert(! full); + return CmpUnknown; +} + +int +NdbSqlUtil::cmpDouble(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +{ + if (n2 >= sizeof(double)) { + double v1, v2; + memcpy(&v1, p1, sizeof(double)); + memcpy(&v2, p2, sizeof(double)); + if (v1 < v2) + return -1; + if (v1 > v2) + return +1; + return 0; + } + assert(! full); + return CmpUnknown; +} + +int +NdbSqlUtil::cmp_olddecimal(const uchar* s1, const uchar* s2, unsigned n) +{ + int sgn = +1; + unsigned i = 0; + while (i < n) { + int c1 = s1[i]; + int c2 = s2[i]; + if (c1 == c2) { + if (c1 == '-') + sgn = -1; + } else if (c1 == '-') { + return -1; + } else if (c2 == '-') { + return +1; + } else if (c1 < c2) { + return -1 * sgn; + } else { + return +1 * sgn; + } + i++; + } + return 0; +} + +int +NdbSqlUtil::cmpOlddecimal(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +{ + if (full) { + assert(n1 == n2); + const uchar* v1 = (const uchar*)p1; + const uchar* v2 = (const uchar*)p2; + return cmp_olddecimal(v1, v2, n1); + } + return CmpUnknown; +} + +int +NdbSqlUtil::cmpOlddecimalunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +{ + if (full) { + assert(n1 == n2); + const uchar* v1 = (const uchar*)p1; + const uchar* v2 = (const uchar*)p2; + return cmp_olddecimal(v1, v2, n1); + } + return CmpUnknown; +} + +int +NdbSqlUtil::cmpDecimal(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +{ + const uchar* v1 = (const uchar*)p1; + const uchar* v2 = (const uchar*)p2; + // compare as binary strings + unsigned n = (n1 <= n2 ? n1 : n2); + int k = memcmp(v1, v2, n); + if (k == 0) { + k = (full ? n1 : n) - n2; + } + return k < 0 ? -1 : k > 0 ? +1 : full ? 0 : CmpUnknown; +} + +int +NdbSqlUtil::cmpDecimalunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +{ + const uchar* v1 = (const uchar*)p1; + const uchar* v2 = (const uchar*)p2; + // compare as binary strings + unsigned n = (n1 <= n2 ? n1 : n2); + int k = memcmp(v1, v2, n); + if (k == 0) { + k = (full ? n1 : n) - n2; + } + return k < 0 ? -1 : k > 0 ? +1 : full ? 0 : CmpUnknown; +} + +int +NdbSqlUtil::cmpChar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +{ + // collation does not work on prefix for some charsets + assert(full); + const uchar* v1 = (const uchar*)p1; + const uchar* v2 = (const uchar*)p2; + // not const in MySQL + CHARSET_INFO* cs = (CHARSET_INFO*)(info); + // compare with space padding + int k = (*cs->coll->strnncollsp)(cs, v1, n1, v2, n2, false); + return k < 0 ? -1 : k > 0 ? +1 : 0; +} + +int +NdbSqlUtil::cmpVarchar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +{ + const unsigned lb = 1; + // collation does not work on prefix for some charsets + assert(full && n1 >= lb && n2 >= lb); + const uchar* v1 = (const uchar*)p1; + const uchar* v2 = (const uchar*)p2; + unsigned m1 = *v1; + unsigned m2 = *v2; + if (m1 <= n1 - lb && m2 <= n2 - lb) { + CHARSET_INFO* cs = (CHARSET_INFO*)(info); + // compare with space padding + int k = (*cs->coll->strnncollsp)(cs, v1 + lb, m1, v2 + lb, m2, false); + return k < 0 ? -1 : k > 0 ? +1 : 0; + } + // treat bad data as NULL + if (m1 > n1 - lb && m2 <= n2 - lb) + return -1; + if (m1 <= n1 - lb && m2 > n2 - lb) + return +1; + return 0; +} + +int +NdbSqlUtil::cmpBinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +{ + const uchar* v1 = (const uchar*)p1; + const uchar* v2 = (const uchar*)p2; + // compare as binary strings + unsigned n = (n1 <= n2 ? n1 : n2); + int k = memcmp(v1, v2, n); + if (k == 0) { + k = (full ? n1 : n) - n2; + } + return k < 0 ? -1 : k > 0 ? +1 : full ? 0 : CmpUnknown; +} + +int +NdbSqlUtil::cmpVarbinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +{ + const unsigned lb = 1; + if (n2 >= lb) { + assert(n1 >= lb); + const uchar* v1 = (const uchar*)p1; + const uchar* v2 = (const uchar*)p2; + unsigned m1 = *v1; + unsigned m2 = *v2; + if (m1 <= n1 - lb && m2 <= n2 - lb) { + // compare as binary strings + unsigned m = (m1 <= m2 ? m1 : m2); + int k = memcmp(v1 + lb, v2 + lb, m); + if (k == 0) { + k = (full ? m1 : m) - m2; + } + return k < 0 ? -1 : k > 0 ? +1 : full ? 0 : CmpUnknown; + } + // treat bad data as NULL + if (m1 > n1 - lb && m2 <= n2 - lb) + return -1; + if (m1 <= n1 - lb && m2 > n2 - lb) + return +1; + return 0; + } + assert(! full); + return CmpUnknown; +} + +int +NdbSqlUtil::cmpDatetime(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +{ + if (n2 >= sizeof(Int64)) { + Int64 v1, v2; + memcpy(&v1, p1, sizeof(Int64)); + memcpy(&v2, p2, sizeof(Int64)); + if (v1 < v2) + return -1; + if (v1 > v2) + return +1; + return 0; + } + assert(! full); + return CmpUnknown; +} + +int +NdbSqlUtil::cmpDate(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +{ +#ifdef ndb_date_is_4_byte_native_int + if (n2 >= sizeof(Int32)) { + Int32 v1, v2; + memcpy(&v1, p1, sizeof(Int32)); + memcpy(&v2, p2, sizeof(Int32)); + if (v1 < v2) + return -1; + if (v1 > v2) + return +1; + return 0; + } +#else +#ifdef ndb_date_sol9x86_cc_xO3_madness + if (n2 >= 3) { + const uchar* v1 = (const uchar*)p1; + const uchar* v2 = (const uchar*)p2; + // from Field_newdate::val_int + Uint64 j1 = uint3korr(v1); + Uint64 j2 = uint3korr(v2); + j1 = (j1 % 32L)+(j1 / 32L % 16L)*100L + (j1/(16L*32L))*10000L; + j2 = (j2 % 32L)+(j2 / 32L % 16L)*100L + (j2/(16L*32L))*10000L; + if (j1 < j2) + return -1; + if (j1 > j2) + return +1; + return 0; + } +#else + if (n2 >= 3) { + const uchar* v1 = (const uchar*)p1; + const uchar* v2 = (const uchar*)p2; + uint j1 = uint3korr(v1); + uint j2 = uint3korr(v2); + uint d1 = (j1 & 31); + uint d2 = (j2 & 31); + j1 = (j1 >> 5); + j2 = (j2 >> 5); + uint m1 = (j1 & 15); + uint m2 = (j2 & 15); + j1 = (j1 >> 4); + j2 = (j2 >> 4); + uint y1 = j1; + uint y2 = j2; + if (y1 < y2) + return -1; + if (y1 > y2) + return +1; + if (m1 < m2) + return -1; + if (m1 > m2) + return +1; + if (d1 < d2) + return -1; + if (d1 > d2) + return +1; + return 0; + } +#endif +#endif + assert(! full); + return CmpUnknown; +} + +// not supported +int +NdbSqlUtil::cmpBlob(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +{ + assert(false); + return 0; +} + +// not supported +int +NdbSqlUtil::cmpText(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +{ + assert(false); + return 0; +} + +int +NdbSqlUtil::cmpTime(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +{ + if (n2 >= 3) { + const uchar* v1 = (const uchar*)p1; + const uchar* v2 = (const uchar*)p2; + // from Field_time::val_int + Int32 j1 = sint3korr(v1); + Int32 j2 = sint3korr(v2); + if (j1 < j2) + return -1; + if (j1 > j2) + return +1; + return 0; + } + assert(! full); + return CmpUnknown; +} + +// not yet +int +NdbSqlUtil::cmpBit(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +{ + assert(false); + return 0; +} + +int +NdbSqlUtil::cmpLongvarchar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +{ + const unsigned lb = 2; + // collation does not work on prefix for some charsets + assert(full && n1 >= lb && n2 >= lb); + const uchar* v1 = (const uchar*)p1; + const uchar* v2 = (const uchar*)p2; + unsigned m1 = uint2korr(v1); + unsigned m2 = uint2korr(v2); + if (m1 <= n1 - lb && m2 <= n2 - lb) { + CHARSET_INFO* cs = (CHARSET_INFO*)(info); + // compare with space padding + int k = (*cs->coll->strnncollsp)(cs, v1 + lb, m1, v2 + lb, m2, false); + return k < 0 ? -1 : k > 0 ? +1 : 0; + } + // treat bad data as NULL + if (m1 > n1 - lb && m2 <= n2 - lb) + return -1; + if (m1 <= n1 - lb && m2 > n2 - lb) + return +1; + return 0; +} + +int +NdbSqlUtil::cmpLongvarbinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +{ + const unsigned lb = 2; + if (n2 >= lb) { + assert(n1 >= lb); + const uchar* v1 = (const uchar*)p1; + const uchar* v2 = (const uchar*)p2; + unsigned m1 = uint2korr(v1); + unsigned m2 = uint2korr(v2); + if (m1 <= n1 - lb && m2 <= n2 - lb) { + // compare as binary strings + unsigned m = (m1 <= m2 ? m1 : m2); + int k = memcmp(v1 + lb, v2 + lb, m); + if (k == 0) { + k = (full ? m1 : m) - m2; + } + return k < 0 ? -1 : k > 0 ? +1 : full ? 0 : CmpUnknown; + } + // treat bad data as NULL + if (m1 > n1 - lb && m2 <= n2 - lb) + return -1; + if (m1 <= n1 - lb && m2 > n2 - lb) + return +1; + return 0; + } + assert(! full); + return CmpUnknown; +} + +int +NdbSqlUtil::cmpYear(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +{ + if (n2 >= sizeof(Uint8)) { + Uint8 v1, v2; + memcpy(&v1, p1, sizeof(Uint8)); + memcpy(&v2, p2, sizeof(Uint8)); + if (v1 < v2) + return -1; + if (v1 > v2) + return +1; + return 0; + } + assert(! full); + return CmpUnknown; +} + +int +NdbSqlUtil::cmpTimestamp(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +{ + if (n2 >= sizeof(Uint32)) { + Uint32 v1, v2; + memcpy(&v1, p1, sizeof(Uint32)); + memcpy(&v2, p2, sizeof(Uint32)); + if (v1 < v2) + return -1; + if (v1 > v2) + return +1; + return 0; + } + assert(! full); + return CmpUnknown; +} + +// like + +static const int ndb_wild_prefix = '\\'; +static const int ndb_wild_one = '_'; +static const int ndb_wild_many = '%'; + +int +NdbSqlUtil::likeChar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2) +{ + const char* v1 = (const char*)p1; + const char* v2 = (const char*)p2; + CHARSET_INFO* cs = (CHARSET_INFO*)(info); + int k = (cs->coll->wildcmp)(cs, v1, v1 + n1, v2, v2 + n2, ndb_wild_prefix, ndb_wild_one, ndb_wild_many); + return k == 0 ? 0 : +1; +} + +int +NdbSqlUtil::likeBinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2) +{ + assert(info == 0); + return likeChar(&my_charset_bin, p1, n1, p2, n2); +} + +int +NdbSqlUtil::likeVarchar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2) +{ + const unsigned lb = 1; + if (n1 >= lb && n2 >= lb) { + const uchar* v1 = (const uchar*)p1; + const uchar* v2 = (const uchar*)p2; + unsigned m1 = *v1; + unsigned m2 = *v2; + if (lb + m1 <= n1 && lb + m2 <= n2) { + const char* w1 = (const char*)v1 + lb; + const char* w2 = (const char*)v2 + lb; + CHARSET_INFO* cs = (CHARSET_INFO*)(info); + int k = (cs->coll->wildcmp)(cs, w1, w1 + m1, w2, w2 + m2, ndb_wild_prefix, ndb_wild_one, ndb_wild_many); + return k == 0 ? 0 : +1; + } + } + return -1; +} + +int +NdbSqlUtil::likeVarbinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2) +{ + assert(info == 0); + return likeVarchar(&my_charset_bin, p1, n1, p2, n2); +} + +int +NdbSqlUtil::likeLongvarchar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2) +{ + const unsigned lb = 2; + if (n1 >= lb && n2 >= lb) { + const uchar* v1 = (const uchar*)p1; + const uchar* v2 = (const uchar*)p2; + unsigned m1 = uint2korr(v1); + unsigned m2 = uint2korr(v2); + if (lb + m1 <= n1 && lb + m2 <= n2) { + const char* w1 = (const char*)v1 + lb; + const char* w2 = (const char*)v2 + lb; + CHARSET_INFO* cs = (CHARSET_INFO*)(info); + int k = (cs->coll->wildcmp)(cs, w1, w1 + m1, w2, w2 + m2, ndb_wild_prefix, ndb_wild_one, ndb_wild_many); + return k == 0 ? 0 : +1; + } + } + return -1; +} + +int +NdbSqlUtil::likeLongvarbinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2) +{ + assert(info == 0); + return likeLongvarchar(&my_charset_bin, p1, n1, p2, n2); +} + +// check charset + +bool +NdbSqlUtil::usable_in_pk(Uint32 typeId, const void* info) +{ + const Type& type = getType(typeId); + switch (type.m_typeId) { + case Type::Char: + case Type::Varchar: + case Type::Longvarchar: + { + const CHARSET_INFO *cs = (const CHARSET_INFO*)info; + return + cs != 0 && + cs->cset != 0 && + cs->coll != 0 && + cs->coll->strnxfrm != 0 && + cs->strxfrm_multiply <= MAX_XFRM_MULTIPLY; + } + break; + case Type::Undefined: + case Type::Blob: + case Type::Text: + case Type::Bit: + break; + default: + return true; + } + return false; +} + +bool +NdbSqlUtil::usable_in_hash_index(Uint32 typeId, const void* info) +{ + return usable_in_pk(typeId, info); +} + +bool +NdbSqlUtil::usable_in_ordered_index(Uint32 typeId, const void* info) +{ + const Type& type = getType(typeId); + if (type.m_cmp == NULL) + return false; + switch (type.m_typeId) { + case Type::Char: + case Type::Varchar: + case Type::Longvarchar: + { + const CHARSET_INFO *cs = (const CHARSET_INFO*)info; + return + cs != 0 && + cs->cset != 0 && + cs->coll != 0 && + cs->coll->strnxfrm != 0 && + cs->coll->strnncollsp != 0 && + cs->strxfrm_multiply <= MAX_XFRM_MULTIPLY; + } + break; + case Type::Undefined: + case Type::Blob: + case Type::Text: + case Type::Bit: // can be fixed + break; + default: + return true; + } + return false; +} + +// utilities + +bool +NdbSqlUtil::get_var_length(Uint32 typeId, const void* p, unsigned attrlen, Uint32& lb, Uint32& len) +{ + const unsigned char* const src = (const unsigned char*)p; + switch (typeId) { + case NdbSqlUtil::Type::Varchar: + case NdbSqlUtil::Type::Varbinary: + lb = 1; + if (attrlen >= lb) { + len = src[0]; + if (attrlen >= lb + len) + return true; + } + break; + case NdbSqlUtil::Type::Longvarchar: + case NdbSqlUtil::Type::Longvarbinary: + lb = 2; + if (attrlen >= lb) { + len = src[0] + (src[1] << 8); + if (attrlen >= lb + len) + return true; + } + break; + default: + lb = 0; + len = attrlen; + return true; + break; + } + return false; +} + +// workaround + +int +NdbSqlUtil::strnxfrm_bug7284(CHARSET_INFO* cs, unsigned char* dst, unsigned dstLen, const unsigned char*src, unsigned srcLen) +{ + unsigned char nsp[20]; // native space char + unsigned char xsp[20]; // strxfrm-ed space char +#ifdef VM_TRACE + memset(nsp, 0x1f, sizeof(nsp)); + memset(xsp, 0x1f, sizeof(xsp)); +#endif + // convert from unicode codepoint for space + int n1 = (*cs->cset->wc_mb)(cs, (my_wc_t)0x20, nsp, nsp + sizeof(nsp)); + if (n1 <= 0) + return -1; + // strxfrm to binary + int n2 = (*cs->coll->strnxfrm)(cs, xsp, sizeof(xsp), nsp, n1); + if (n2 <= 0) + return -1; + // XXX bug workaround - strnxfrm may not write full string + memset(dst, 0x0, dstLen); + // strxfrm argument string - returns no error indication + int n3 = (*cs->coll->strnxfrm)(cs, dst, dstLen, src, srcLen); + // pad with strxfrm-ed space chars + int n4 = n3; + while (n4 < (int)dstLen) { + dst[n4] = xsp[(n4 - n3) % n2]; + n4++; + } + // no check for partial last + return dstLen; +} diff --git a/storage/ndb/src/common/util/OutputStream.cpp b/storage/ndb/src/common/util/OutputStream.cpp new file mode 100644 index 00000000000..a41eef649dd --- /dev/null +++ b/storage/ndb/src/common/util/OutputStream.cpp @@ -0,0 +1,99 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +#include <ndb_global.h> + +#include <OutputStream.hpp> +#include <socket_io.h> + +FileOutputStream::FileOutputStream(FILE * file){ + f = file; +} + +int +FileOutputStream::print(const char * fmt, ...){ + va_list ap; + va_start(ap, fmt); + const int ret = vfprintf(f, fmt, ap); + va_end(ap); + return ret; +} + +int +FileOutputStream::println(const char * fmt, ...){ + va_list ap; + va_start(ap, fmt); + const int ret = vfprintf(f, fmt, ap); + va_end(ap); + return ret + fprintf(f, "\n"); +} + +SocketOutputStream::SocketOutputStream(NDB_SOCKET_TYPE socket, + unsigned timeout){ + m_socket = socket; + m_timeout = timeout; +} + +int +SocketOutputStream::print(const char * fmt, ...){ + va_list ap; + va_start(ap, fmt); + const int ret = vprint_socket(m_socket, m_timeout, fmt, ap); + va_end(ap); + return ret; +} +int +SocketOutputStream::println(const char * fmt, ...){ + va_list ap; + va_start(ap, fmt); + const int ret = vprintln_socket(m_socket, m_timeout, fmt, ap); + va_end(ap); + return ret; +} + +#ifdef NDB_SOFTOSE +#include <dbgprintf.h> +int +SoftOseOutputStream::print(const char * fmt, ...){ + va_list ap; + char buf[1000]; + + va_start(ap, fmt); + if (fmt != 0) + BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap); + else + buf[0] = 0; + va_end(ap); + dbgprintf(buf); +} + +int +SoftOseOutputStream::println(const char * fmt, ...){ + va_list ap; + char buf[1000]; + + va_start(ap, fmt); + if (fmt != 0) + BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap); + else + buf[0] = 0; + va_end(ap); + + strcat(buf, "\n\r"); + dbgprintf(buf); +} +#endif diff --git a/storage/ndb/src/common/util/Parser.cpp b/storage/ndb/src/common/util/Parser.cpp new file mode 100644 index 00000000000..dea128ccf66 --- /dev/null +++ b/storage/ndb/src/common/util/Parser.cpp @@ -0,0 +1,350 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +#include <ndb_global.h> + +#include "Parser.hpp" +#include <NdbOut.hpp> +#include <Properties.hpp> +#include <Base64.hpp> + +#undef DEBUG +#define DEBUG(x) ndbout << x << endl; + +static void trim(char * str); + +class ParseInputStream : public InputStream { +public: + ParseInputStream(InputStream & in, bool trim = true, char eofComment = '#'); + + char* gets(char * buf, int bufLen); + void push_back(const char *); +private: + InputStream & in; + char * buffer; +}; + +ParseInputStream::ParseInputStream(InputStream & _in, + bool /* unused */, + char /* unused */) + : in(_in){ + buffer = 0; +} + +char* +ParseInputStream::gets(char * buf, int bufLen){ + if(buffer != 0){ + strncpy(buf, buffer, bufLen); + free(buffer); + buffer = 0; + return buf; + } + char *t = in.gets(buf, bufLen); + return t; +} + +void +ParseInputStream::push_back(const char * str){ + if(buffer != 0) + abort(); + buffer = strdup(str); +} + +ParserImpl::ParserImpl(const DummyRow * rows, InputStream & in, + bool b_cmd, bool b_empty, bool b_iarg) + : m_rows(rows), input(* new ParseInputStream(in)) +{ + m_breakOnCmd = b_cmd; + m_breakOnEmpty = b_empty; + m_breakOnInvalidArg = b_iarg; +} + +ParserImpl::~ParserImpl(){ + delete & input; +} + +static +bool +Empty(const char * str){ + if(str == 0) + return true; + const int len = strlen(str); + if(len == 0) + return false; + for(int i = 0; i<len; i++) + if(str[i] != ' ' && str[i] != '\t' && str[i] != '\n') + return false; + return true; +} + +static +bool +Eof(const char * str) { return str == 0;} + +static +void +trim(char * str){ + if(str == NULL) + return; + int len = strlen(str); + for(len--; str[len] == '\n' || str[len] == ' ' || str[len] == '\t'; len--) + str[len] = 0; + + int pos = 0; + while(str[pos] == ' ' || str[pos] == '\t') + pos++; + + if(str[pos] == '\"' && str[len] == '\"') { + pos++; + str[len] = 0; + len--; + } + + memmove(str, &str[pos], len - pos + 2); +} + +static +bool +split(char * buf, char ** name, char ** value){ + + * value = strchr(buf, ':'); + if(* value == 0) + * value = strchr(buf, '='); + + + if(* value == 0){ + return false; + } + (* value)[0] = 0; + * value = (* value + 1); + * name = buf; + + trim(* name); + trim(* value); + + return true; +} + +bool +ParserImpl::run(Context * ctx, const class Properties ** pDst, + volatile bool * stop) const { + * pDst = 0; + bool ownStop = false; + if(stop == 0) + stop = &ownStop; + + ctx->m_aliasUsed.clear(); + + const unsigned sz = sizeof(ctx->m_tokenBuffer); + ctx->m_currentToken = input.gets(ctx->m_tokenBuffer, sz); + if(Eof(ctx->m_currentToken)){ + ctx->m_status = Parser<Dummy>::Eof; + return false; + } + + if(ctx->m_currentToken[0] == 0){ + ctx->m_status = Parser<Dummy>::NoLine; + return false; + } + + if(Empty(ctx->m_currentToken)){ + ctx->m_status = Parser<Dummy>::EmptyLine; + return false; + } + + trim(ctx->m_currentToken); + ctx->m_currentCmd = matchCommand(ctx, ctx->m_currentToken, m_rows); + if(ctx->m_currentCmd == 0){ + ctx->m_status = Parser<Dummy>::UnknownCommand; + return false; + } + + Properties * p = new Properties(); + + bool invalidArgument = false; + ctx->m_currentToken = input.gets(ctx->m_tokenBuffer, sz); + + while((! * stop) && + !Eof(ctx->m_currentToken) && + !Empty(ctx->m_currentToken)){ + if(ctx->m_currentToken[0] != 0){ + trim(ctx->m_currentToken); + if(!parseArg(ctx, ctx->m_currentToken, ctx->m_currentCmd + 1, p)){ + delete p; + invalidArgument = true; + break; + } + } + ctx->m_currentToken = input.gets(ctx->m_tokenBuffer, sz); + } + + if(invalidArgument){ + char buf[sz]; + char * tmp; + if(!m_breakOnInvalidArg){ + do { + tmp = input.gets(buf, sz); + } while((! * stop) && !Eof(tmp) && !Empty(tmp)); + } + return false; + } + + if(* stop){ + delete p; + ctx->m_status = Parser<Dummy>::ExternalStop; + return false; + } + + if(!checkMandatory(ctx, p)){ + ctx->m_status = Parser<Dummy>::MissingMandatoryArgument; + delete p; + return false; + } + + /** + * Add alias to properties + */ + for(unsigned i = 0; i<ctx->m_aliasUsed.size(); i++){ + const ParserRow<Dummy> * alias = ctx->m_aliasUsed[i]; + Properties tmp; + tmp.put("name", alias->name); + tmp.put("realName", alias->realName); + p->put("$ALIAS", i, &tmp); + } + p->put("$ALIAS", ctx->m_aliasUsed.size()); + + ctx->m_status = Parser<Dummy>::Ok; + * pDst = p; + return true; +} + +const ParserImpl::DummyRow* +ParserImpl::matchCommand(Context* ctx, const char* buf, const DummyRow rows[]){ + const char * name = buf; + const DummyRow * tmp = &rows[0]; + while(tmp->name != 0 && name != 0){ + if(strcmp(tmp->name, name) == 0){ + if(tmp->type == DummyRow::Cmd) + return tmp; + if(tmp->type == DummyRow::CmdAlias){ + if(ctx != 0) + ctx->m_aliasUsed.push_back(tmp); + name = tmp->realName; + tmp = &rows[0]; + continue; + } + } + tmp++; + } + return 0; +} + +const ParserImpl::DummyRow* +ParserImpl::matchArg(Context* ctx, const char * buf, const DummyRow rows[]){ + const char * name = buf; + const DummyRow * tmp = &rows[0]; + while(tmp->name != 0){ + const DummyRow::Type t = tmp->type; + if(t != DummyRow::Arg && t != DummyRow::ArgAlias && t !=DummyRow::CmdAlias) + break; + if(t !=DummyRow::CmdAlias && strcmp(tmp->name, name) == 0){ + if(tmp->type == DummyRow::Arg){ + return tmp; + } + if(tmp->type == DummyRow::ArgAlias){ + if(ctx != 0) + ctx->m_aliasUsed.push_back(tmp); + name = tmp->realName; + tmp = &rows[0]; + continue; + } + } + tmp++; + } + return 0; +} + +bool +ParserImpl::parseArg(Context * ctx, + char * buf, + const DummyRow * rows, + Properties * p){ + char * name; + char * value; + if(!split(buf, &name, &value)){ + ctx->m_status = Parser<Dummy>::InvalidArgumentFormat; + return false; + } + const DummyRow * arg = matchArg(ctx, name, rows); + if(arg == 0){ + ctx->m_status = Parser<Dummy>::UnknownArgument; + return false; + } + + switch(arg->argType){ + case DummyRow::String: + if(p->put(arg->name, value)) + return true; + break; + case DummyRow::Int:{ + Uint32 i; + int c = sscanf(value, "%u", &i); + if(c != 1){ + ctx->m_status = Parser<Dummy>::TypeMismatch; + return false; + } + if(p->put(arg->name, i)) + return true; + break; + } + + case DummyRow::Properties: { + Properties *sp = new Properties(); + BaseString v(value); + UtilBuffer b; + base64_decode(v, b); + sp->unpack((const Uint32 *)b.get_data(), b.length()); + break; + } + default: + ctx->m_status = Parser<Dummy>::UnknownArgumentType; + return false; + } + if(p->getPropertiesErrno() == E_PROPERTIES_ELEMENT_ALREADY_EXISTS){ + ctx->m_status = Parser<Dummy>::ArgumentGivenTwice; + return false; + } + + abort(); +} + +bool +ParserImpl::checkMandatory(Context* ctx, const Properties* props){ + const DummyRow * tmp = &ctx->m_currentCmd[1]; + while(tmp->name != 0 && tmp->type == DummyRow::Arg){ + if(tmp->argRequired == ParserRow<Dummy>::Mandatory && + !props->contains(tmp->name)){ + ctx->m_status = Parser<Dummy>::MissingMandatoryArgument; + ctx->m_currentArg = tmp; + return false; + } + tmp++; + } + return true; +} + +template class Vector<const ParserRow<ParserImpl::Dummy>*>; diff --git a/storage/ndb/src/common/util/Properties.cpp b/storage/ndb/src/common/util/Properties.cpp new file mode 100644 index 00000000000..0edcda0e726 --- /dev/null +++ b/storage/ndb/src/common/util/Properties.cpp @@ -0,0 +1,1136 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <ndb_global.h> + +#include <Properties.hpp> + +#include <NdbTCP.h> +#include <NdbOut.hpp> + +static +char * f_strdup(const char * s){ + if(!s) return 0; + return strdup(s); +} + +/** + * Note has to be a multiple of 4 bytes + */ +const char Properties::version[] = { 2, 0, 0, 1, 1, 1, 1, 4 }; +const char Properties::delimiter = ':'; + +/** + * PropertyImpl + */ +struct PropertyImpl{ + PropertiesType valueType; + const char * name; + void * value; + + ~PropertyImpl(); + PropertyImpl(const char * name, Uint32 value); + PropertyImpl(const char * name, Uint64 value); + PropertyImpl(const char * name, const char * value); + PropertyImpl(const char * name, const Properties * value); + + static PropertyImpl * copyPropertyImpl(const PropertyImpl &); +}; + +/** + * PropertiesImpl + */ +class PropertiesImpl { + PropertiesImpl(const PropertiesImpl &); // Not implemented + PropertiesImpl& operator=(const PropertiesImpl&); // Not implemented +public: + PropertiesImpl(Properties *, bool case_insensitive); + PropertiesImpl(Properties *, const PropertiesImpl &); + ~PropertiesImpl(); + + Properties * properties; + + Uint32 size; + Uint32 items; + PropertyImpl **content; + + bool m_insensitive; + int (* compare)(const char *s1, const char *s2); + + void setCaseInsensitiveNames(bool value); + void grow(int sizeToAdd); + + PropertyImpl * get(const char * name) const; + PropertyImpl * put(PropertyImpl *); + void remove(const char * name); + + Uint32 getPackedSize(Uint32 pLen) const; + bool pack(Uint32 *& buf, const char * prefix, Uint32 prefixLen) const; + bool unpack(const Uint32 * buf, Uint32 &bufLen, Properties * top, int items); + + Uint32 getTotalItems() const; + + void setErrno(Uint32 pErr, Uint32 osErr = 0){ + properties->setErrno(pErr, osErr); + } + + const char * getProps(const char * name, const PropertiesImpl ** impl) const; + const char * getPropsPut(const char * name, PropertiesImpl ** impl); +}; + +/** + * Methods for Property + */ +Property::Property(const char * name, Uint32 value){ + impl = new PropertyImpl(name, value); +} + +Property::Property(const char * name, const char * value){ + impl = new PropertyImpl(name, value); +} + +Property::Property(const char * name, const class Properties * value){ + impl = new PropertyImpl(name, value); + + ((Properties*)impl->value)->setCaseInsensitiveNames(value->getCaseInsensitiveNames()); +} + +Property::~Property(){ + delete impl; +} + +/** + * Methods for Properties + */ +Properties::Properties(bool case_insensitive){ + parent = 0; + impl = new PropertiesImpl(this, case_insensitive); +} + +Properties::Properties(const Properties & org){ + parent = 0; + impl = new PropertiesImpl(this, * org.impl); +} + +Properties::Properties(const Property * anArray, int arrayLen){ + impl = new PropertiesImpl(this, false); + + put(anArray, arrayLen); +} + +Properties::~Properties(){ + clear(); + delete impl; +} + +void +Properties::put(const Property * anArray, int arrayLen){ + if(anArray == 0) + return; + for(int i = 0; i<arrayLen; i++) + impl->put(anArray[i].impl); +} + +template <class T> +bool +put(PropertiesImpl * impl, const char * name, T value, bool replace){ + if(name == 0){ + impl->setErrno(E_PROPERTIES_INVALID_NAME); + return false; + } + + PropertiesImpl * tmp = 0; + const char * short_name = impl->getPropsPut(name, &tmp); + + if(tmp == 0){ + impl->setErrno(E_PROPERTIES_NO_SUCH_ELEMENT); + return false; + } + + if(tmp->get(short_name) != 0){ + if(replace){ + tmp->remove(short_name); + } else { + impl->setErrno(E_PROPERTIES_ELEMENT_ALREADY_EXISTS); + return false; + } + } + return tmp->put(new PropertyImpl(short_name, value)); +} + + +bool +Properties::put(const char * name, Uint32 value, bool replace){ + return ::put(impl, name, value, replace); +} + +bool +Properties::put64(const char * name, Uint64 value, bool replace){ + return ::put(impl, name, value, replace); +} + +bool +Properties::put(const char * name, const char * value, bool replace){ + return ::put(impl, name, value, replace); +} + +bool +Properties::put(const char * name, const Properties * value, bool replace){ + return ::put(impl, name, value, replace); +} + +bool +Properties::getTypeOf(const char * name, PropertiesType * type) const { + PropertyImpl * nvp = impl->get(name); + if(nvp == 0){ + setErrno(E_PROPERTIES_NO_SUCH_ELEMENT); + return false; + } + setErrno(E_PROPERTIES_OK); + * type = nvp->valueType; + return true; +} + +bool +Properties::contains(const char * name) const { + PropertyImpl * nvp = impl->get(name); + return nvp != 0; +} + +bool +Properties::get(const char * name, Uint32 * value) const { + PropertyImpl * nvp = impl->get(name); + if(nvp == 0){ + setErrno(E_PROPERTIES_NO_SUCH_ELEMENT); + return false; + } + + if(nvp->valueType == PropertiesType_Uint32){ + * value = * (Uint32 *)nvp->value; + setErrno(E_PROPERTIES_OK); + return true; + } + + if(nvp->valueType == PropertiesType_Uint64){ + Uint64 tmp = * (Uint64 *)nvp->value; + Uint64 max = 1; max <<= 32; + if(tmp < max){ + * value = (Uint32)tmp; + setErrno(E_PROPERTIES_OK); + return true; + } + } + setErrno(E_PROPERTIES_INVALID_TYPE); + return false; +} + +bool +Properties::get(const char * name, Uint64 * value) const { + PropertyImpl * nvp = impl->get(name); + if(nvp == 0){ + setErrno(E_PROPERTIES_NO_SUCH_ELEMENT); + return false; + } + + if(nvp->valueType == PropertiesType_Uint32){ + Uint32 tmp = * (Uint32 *)nvp->value; + * value = (Uint64)tmp; + setErrno(E_PROPERTIES_OK); + return true; + } + + if(nvp->valueType == PropertiesType_Uint64){ + * value = * (Uint64 *)nvp->value; + setErrno(E_PROPERTIES_OK); + return true; + } + setErrno(E_PROPERTIES_INVALID_TYPE); + return false; +} + +bool +Properties::get(const char * name, const char ** value) const { + PropertyImpl * nvp = impl->get(name); + if(nvp == 0){ + setErrno(E_PROPERTIES_NO_SUCH_ELEMENT); + return false; + } + + if(nvp->valueType == PropertiesType_char){ + * value = (const char *)nvp->value; + setErrno(E_PROPERTIES_OK); + return true; + } + setErrno(E_PROPERTIES_INVALID_TYPE); + return false; +} + +bool +Properties::get(const char * name, BaseString& value) const { + const char *tmp = ""; + bool ret; + ret = get(name, &tmp); + value.assign(tmp); + return ret; +} + +bool +Properties::get(const char * name, const Properties ** value) const { + PropertyImpl * nvp = impl->get(name); + if(nvp == 0){ + setErrno(E_PROPERTIES_NO_SUCH_ELEMENT); + return false; + } + if(nvp->valueType == PropertiesType_Properties){ + * value = (const Properties *)nvp->value; + setErrno(E_PROPERTIES_OK); + return true; + } + setErrno(E_PROPERTIES_INVALID_TYPE); + return false; +} + +bool +Properties::getCopy(const char * name, char ** value) const { + PropertyImpl * nvp = impl->get(name); + if(nvp == 0){ + setErrno(E_PROPERTIES_NO_SUCH_ELEMENT); + return false; + } + + if(nvp->valueType == PropertiesType_char){ + * value = f_strdup((const char *)nvp->value); + setErrno(E_PROPERTIES_OK); + return true; + } + setErrno(E_PROPERTIES_INVALID_TYPE); + return false; +} + +bool +Properties::getCopy(const char * name, Properties ** value) const { + PropertyImpl * nvp = impl->get(name); + if(nvp == 0){ + setErrno(E_PROPERTIES_NO_SUCH_ELEMENT); + return false; + } + + if(nvp->valueType == PropertiesType_Properties){ + * value = new Properties(* (const Properties *)nvp->value); + setErrno(E_PROPERTIES_OK); + return true; + } + setErrno(E_PROPERTIES_INVALID_TYPE); + return false; +} + +void +Properties::clear(){ + while(impl->items > 0) + impl->remove(impl->content[0]->name); +} + +void +Properties::remove(const char * name) { + impl->remove(name); +} + +void +Properties::print(FILE * out, const char * prefix) const{ + char buf[1024]; + if(prefix == 0) + buf[0] = 0; + else + strncpy(buf, prefix, 1024); + + for(unsigned int i = 0; i<impl->items; i++){ + switch(impl->content[i]->valueType){ + case PropertiesType_Uint32: + fprintf(out, "%s%s = (Uint32) %d\n", buf, impl->content[i]->name, + *(Uint32 *)impl->content[i]->value); + break; + case PropertiesType_Uint64: + fprintf(out, "%s%s = (Uint64) %lld\n", buf, impl->content[i]->name, + *(Uint64 *)impl->content[i]->value); + break; + case PropertiesType_char: + fprintf(out, "%s%s = (char*) \"%s\"\n", buf, impl->content[i]->name, + (char *)impl->content[i]->value); + break; + case PropertiesType_Properties: + char buf2 [1024]; + BaseString::snprintf(buf2, sizeof(buf2), "%s%s%c",buf, impl->content[i]->name, + Properties::delimiter); + ((Properties *)impl->content[i]->value)->print(out, buf2); + break; + } + } +} + +Properties::Iterator::Iterator(const Properties* prop) : + m_prop(prop), + m_iterator(0) { +} + +const char* +Properties::Iterator::first() { + m_iterator = 0; + return next(); +} + +const char* +Properties::Iterator::next() { + if (m_iterator < m_prop->impl->items) + return m_prop->impl->content[m_iterator++]->name; + else + return NULL; +} + +Uint32 +Properties::getPackedSize() const { + Uint32 sz = 0; + + sz += sizeof(version); // Version id of properties object + sz += 4; // No Of Items + sz += 4; // Checksum + + return sz + impl->getPackedSize(0); +} + +static +Uint32 +computeChecksum(const Uint32 * buf, Uint32 words){ + Uint32 sum = 0; + for(unsigned int i = 0; i<words; i++) + sum ^= htonl(buf[i]); + + return sum; +} + +bool +Properties::pack(Uint32 * buf) const { + Uint32 * bufStart = buf; + + memcpy(buf, version, sizeof(version)); + + // Note that version must be a multiple of 4 + buf += (sizeof(version) / 4); + + * buf = htonl(impl->getTotalItems()); + buf++; + bool res = impl->pack(buf, "", 0); + if(!res) + return res; + + * buf = htonl(computeChecksum(bufStart, (buf - bufStart))); + + return true; +} + +bool +Properties::unpack(const Uint32 * buf, Uint32 bufLen){ + const Uint32 * bufStart = buf; + Uint32 bufLenOrg = bufLen; + + if(bufLen < sizeof(version)){ + setErrno(E_PROPERTIES_INVALID_BUFFER_TO_SHORT); + return false; + } + + if(memcmp(buf, version, sizeof(version)) != 0){ + setErrno(E_PROPERTIES_INVALID_VERSION_WHILE_UNPACKING); + return false; + } + bufLen -= sizeof(version); + + // Note that version must be a multiple of 4 + buf += (sizeof(version) / 4); + + if(bufLen < 4){ + setErrno(E_PROPERTIES_INVALID_BUFFER_TO_SHORT); + return false; + } + + Uint32 totalItems = ntohl(* buf); + buf++; bufLen -= 4; + bool res = impl->unpack(buf, bufLen, this, totalItems); + if(!res) + return res; + + Uint32 sum = computeChecksum(bufStart, (bufLenOrg-bufLen)/4); + if(sum != ntohl(bufStart[(bufLenOrg-bufLen)/4])){ + setErrno(E_PROPERTIES_INVALID_CHECKSUM); + return false; + } + return true; +} + +/** + * Methods for PropertiesImpl + */ +PropertiesImpl::PropertiesImpl(Properties * p, bool case_insensitive){ + this->properties = p; + items = 0; + size = 25; + content = new PropertyImpl * [size]; + setCaseInsensitiveNames(case_insensitive); +} + +PropertiesImpl::PropertiesImpl(Properties * p, const PropertiesImpl & org){ + this->properties = p; + this->size = org.size; + this->items = org.items; + this->m_insensitive = org.m_insensitive; + this->compare = org.compare; + content = new PropertyImpl * [size]; + for(unsigned int i = 0; i<items; i++){ + content[i] = PropertyImpl::copyPropertyImpl(* org.content[i]); + } +} + +PropertiesImpl::~PropertiesImpl(){ + for(unsigned int i = 0; i<items; i++) + delete content[i]; + delete [] content; +} + +void +PropertiesImpl::setCaseInsensitiveNames(bool value){ + m_insensitive = value; + if(value) + compare = strcasecmp; + else + compare = strcmp; +} + +void +PropertiesImpl::grow(int sizeToAdd){ + PropertyImpl ** newContent = new PropertyImpl * [size + sizeToAdd]; + memcpy(newContent, content, items * sizeof(PropertyImpl *)); + delete [] content; + content = newContent; + size += sizeToAdd; +} + +PropertyImpl * +PropertiesImpl::get(const char * name) const { + const PropertiesImpl * tmp = 0; + const char * short_name = getProps(name, &tmp); + if(tmp == 0){ + return 0; + } + + for(unsigned int i = 0; i<tmp->items; i++) { + if((* compare)(tmp->content[i]->name, short_name) == 0) + return tmp->content[i]; + } + + return 0; +} + +PropertyImpl * +PropertiesImpl::put(PropertyImpl * nvp){ + if(items == size) + grow(size); + content[items] = nvp; + + items ++; + + if(nvp->valueType == PropertiesType_Properties){ + ((Properties*)nvp->value)->parent = properties; + } + return nvp; +} + +void +PropertiesImpl::remove(const char * name){ + for(unsigned int i = 0; i<items; i++){ + if((* compare)(content[i]->name, name) == 0){ + delete content[i]; + memmove(&content[i], &content[i+1], (items-i-1)*sizeof(PropertyImpl *)); + items --; + return; + } + } +} + +Uint32 +PropertiesImpl::getTotalItems() const { + int ret = 0; + for(unsigned int i = 0; i<items; i++) + if(content[i]->valueType == PropertiesType_Properties){ + ret += ((Properties*)content[i]->value)->impl->getTotalItems(); + } else { + ret ++; + } + return ret; +} + +const char * +PropertiesImpl::getProps(const char * name, + const PropertiesImpl ** impl) const { + const char * ret = name; + const char * tmp = strchr(name, Properties::delimiter); + if(tmp == 0){ + * impl = this; + return ret; + } else { + Uint32 sz = tmp - name; + char * tmp2 = (char*)malloc(sz + 1); + memcpy(tmp2, name, sz); + tmp2[sz] = 0; + + PropertyImpl * nvp = get(tmp2); + + free(tmp2); + + if(nvp == 0){ + * impl = 0; + return 0; + } + if(nvp->valueType != PropertiesType_Properties){ + * impl = 0; + return name; + } + return ((Properties*)nvp->value)->impl->getProps(tmp+1, impl); + } +} + +const char * +PropertiesImpl::getPropsPut(const char * name, + PropertiesImpl ** impl) { + const char * ret = name; + const char * tmp = strchr(name, Properties::delimiter); + if(tmp == 0){ + * impl = this; + return ret; + } else { + Uint32 sz = tmp - name; + char * tmp2 = (char*)malloc(sz + 1); + memcpy(tmp2, name, sz); + tmp2[sz] = 0; + + PropertyImpl * nvp = get(tmp2); + + if(nvp == 0){ + Properties * tmpP = new Properties(); + PropertyImpl * tmpPI = new PropertyImpl(tmp2, tmpP); + PropertyImpl * nvp = put(tmpPI); + + delete tmpP; + free(tmp2); + return ((Properties*)nvp->value)->impl->getPropsPut(tmp+1, impl); + } + free(tmp2); + if(nvp->valueType != PropertiesType_Properties){ + * impl = 0; + return name; + } + return ((Properties*)nvp->value)->impl->getPropsPut(tmp+1, impl); + } +} + +int +mod4(unsigned int i){ + int res = i + (4 - (i % 4)); + return res; +} + +Uint32 +PropertiesImpl::getPackedSize(Uint32 pLen) const { + Uint32 sz = 0; + for(unsigned int i = 0; i<items; i++){ + if(content[i]->valueType == PropertiesType_Properties){ + Properties * p = (Properties*)content[i]->value; + sz += p->impl->getPackedSize(pLen+strlen(content[i]->name)+1); + } else { + sz += 4; // Type + sz += 4; // Name Len + sz += 4; // Value Len + sz += mod4(pLen + strlen(content[i]->name)); // Name + switch(content[i]->valueType){ + case PropertiesType_char: + sz += mod4(strlen((char *)content[i]->value)); + break; + case PropertiesType_Uint32: + sz += mod4(4); + break; + case PropertiesType_Uint64: + sz += mod4(8); + break; + case PropertiesType_Properties: + default: + assert(0); + } + } + } + return sz; +} + +struct CharBuf { + char * buffer; + Uint32 bufLen; + Uint32 contentLen; + + CharBuf(){ + buffer = 0; + bufLen = 0; + contentLen = 0; + } + + ~CharBuf(){ + free(buffer); + } + + void clear() { contentLen = 0;} + bool add(const char * str, Uint32 strLen){ + if(!expand(contentLen + strLen + 1)) + return false; + memcpy(&buffer[contentLen], str, strLen); + contentLen += strLen; + buffer[contentLen] = 0; + return true; + } + + bool add(char c){ + return add(&c, 1); + } + + bool expand(Uint32 newSize){ + if(newSize >= bufLen){ + + char * tmp = (char*)malloc(newSize + 1024); + memset(tmp, 0, newSize + 1024); + if(tmp == 0) + return false; + if(contentLen > 0) + memcpy(tmp, buffer, contentLen); + if(buffer != 0) + free(buffer); + buffer = tmp; + bufLen = newSize + 1024; + } + return true; + } +}; + +bool +PropertiesImpl::pack(Uint32 *& buf, const char * prefix, Uint32 pLen) const { + CharBuf charBuf; + + for(unsigned int i = 0; i<items; i++){ + const int strLenName = strlen(content[i]->name); + + if(content[i]->valueType == PropertiesType_Properties){ + charBuf.clear(); + if(!charBuf.add(prefix, pLen)){ + properties->setErrno(E_PROPERTIES_ERROR_MALLOC_WHILE_PACKING, + errno); + return false; + } + + if(!charBuf.add(content[i]->name, strLenName)){ + properties->setErrno(E_PROPERTIES_ERROR_MALLOC_WHILE_PACKING, + errno); + return false; + } + + if(!charBuf.add(Properties::delimiter)){ + properties->setErrno(E_PROPERTIES_ERROR_MALLOC_WHILE_PACKING, + errno); + return false; + } + + if(!((Properties*)(content[i]->value))->impl->pack(buf, + charBuf.buffer, + charBuf.contentLen)){ + + return false; + } + continue; + } + + Uint32 valLenData = 0; + Uint32 valLenWrite = 0; + Uint32 sz = 4 + 4 + 4 + mod4(pLen + strLenName); + switch(content[i]->valueType){ + case PropertiesType_Uint32: + valLenData = 4; + break; + case PropertiesType_Uint64: + valLenData = 8; + break; + case PropertiesType_char: + valLenData = strlen((char *)content[i]->value); + break; + case PropertiesType_Properties: + assert(0); + } + valLenWrite = mod4(valLenData); + sz += valLenWrite; + + * (buf + 0) = htonl(content[i]->valueType); + * (buf + 1) = htonl(pLen + strLenName); + * (buf + 2) = htonl(valLenData); + + char * valBuf = (char*)(buf + 3); + char * nameBuf = (char*)(buf + 3 + (valLenWrite / 4)); + + memset(valBuf, 0, sz-12); + + switch(content[i]->valueType){ + case PropertiesType_Uint32: + * (Uint32 *)valBuf = htonl(* (Uint32 *)content[i]->value); + break; + case PropertiesType_Uint64:{ + Uint64 val = * (Uint64 *)content[i]->value; + Uint32 hi = (val >> 32); + Uint32 lo = (val & 0xFFFFFFFF); + * (Uint32 *)valBuf = htonl(hi); + * (Uint32 *)(valBuf + 4) = htonl(lo); + } + break; + case PropertiesType_char: + memcpy(valBuf, content[i]->value, strlen((char*)content[i]->value)); + break; + case PropertiesType_Properties: + assert(0); + } + if(pLen > 0) + memcpy(nameBuf, prefix, pLen); + memcpy(nameBuf + pLen, content[i]->name, strLenName); + + buf += (sz / 4); + } + + return true; +} + +bool +PropertiesImpl::unpack(const Uint32 * buf, Uint32 &bufLen, Properties * top, + int _items){ + CharBuf charBuf; + while(_items > 0){ + Uint32 tmp[3]; + + if(bufLen <= 12){ + top->setErrno(E_PROPERTIES_BUFFER_TO_SMALL_WHILE_UNPACKING); + return false; + } + + tmp[0] = ntohl(buf[0]); + tmp[1] = ntohl(buf[1]); + tmp[2] = ntohl(buf[2]); + buf += 3; + bufLen -= 12; + + PropertiesType pt = (PropertiesType)tmp[0]; + Uint32 nameLen = tmp[1]; + Uint32 valueLen = tmp[2]; + Uint32 nameLenRead = mod4(nameLen); + Uint32 valueLenRead = mod4(valueLen); + + Uint32 sz = nameLenRead + valueLenRead; + if(bufLen < sz){ + top->setErrno(E_PROPERTIES_BUFFER_TO_SMALL_WHILE_UNPACKING); + return false; + } + + if(!charBuf.expand(sz)){ + top->setErrno(E_PROPERTIES_ERROR_MALLOC_WHILE_UNPACKING, errno); + return false; + } + + memcpy(charBuf.buffer, buf, sz); + buf += (sz / 4); + bufLen -= sz ; + + char * valBuf = charBuf.buffer; + char * nameBuf = charBuf.buffer + valueLenRead; + + nameBuf[nameLen] = 0; + valBuf[valueLen] = 0; + + bool res3 = false; + switch(pt){ + case PropertiesType_Uint32: + res3 = top->put(nameBuf, ntohl(* (Uint32 *)valBuf), true); + break; + case PropertiesType_Uint64:{ + Uint64 hi = ntohl(* (Uint32 *)valBuf); + Uint64 lo = ntohl(* (Uint32 *)(valBuf + 4)); + res3 = top->put64(nameBuf, (hi << 32) + lo, true); + } + break; + case PropertiesType_char: + res3 = top->put(nameBuf, valBuf, true); + break; + case PropertiesType_Properties: + assert(0); + } + if(!res3){ + return false; + } + _items--; + } + return true; +} + +PropertyImpl::~PropertyImpl(){ + free((char*)name); + switch(valueType){ + case PropertiesType_Uint32: + delete (Uint32 *)value; + break; + case PropertiesType_Uint64: + delete (Uint64 *)value; + break; + case PropertiesType_char: + free((char *)value); + break; + case PropertiesType_Properties: + delete (Properties *)value; + break; + } +} + +PropertyImpl * +PropertyImpl::copyPropertyImpl(const PropertyImpl & org){ + switch(org.valueType){ + case PropertiesType_Uint32: + return new PropertyImpl(org.name, * (Uint32 *)org.value); + case PropertiesType_Uint64: + return new PropertyImpl(org.name, * (Uint64 *)org.value); + break; + case PropertiesType_char: + return new PropertyImpl(org.name, (char *)org.value); + break; + case PropertiesType_Properties: + return new PropertyImpl(org.name, (Properties *)org.value); + break; + default: + assert(0); + } + return 0; +} + +PropertyImpl::PropertyImpl(const char * _name, Uint32 _value){ + this->name = f_strdup(_name); + this->value = new Uint32; + * ((Uint32 *)this->value) = _value; + this->valueType = PropertiesType_Uint32; +} + +PropertyImpl::PropertyImpl(const char * _name, Uint64 _value){ + this->name = f_strdup(_name); + this->value = new Uint64; + * ((Uint64 *)this->value) = _value; + this->valueType = PropertiesType_Uint64; +} + +PropertyImpl::PropertyImpl(const char * _name, const char * _value){ + this->name = f_strdup(_name); + this->value = f_strdup(_value); + this->valueType = PropertiesType_char; + +} + +PropertyImpl::PropertyImpl(const char * _name, const Properties * _value){ + this->name = f_strdup(_name); + this->value = new Properties(* _value); + this->valueType = PropertiesType_Properties; +} + +const Uint32 E_PROPERTIES_OK = 0; +const Uint32 E_PROPERTIES_INVALID_NAME = 1; +const Uint32 E_PROPERTIES_NO_SUCH_ELEMENT = 2; +const Uint32 E_PROPERTIES_INVALID_TYPE = 3; +const Uint32 E_PROPERTIES_ELEMENT_ALREADY_EXISTS = 4; + +const Uint32 E_PROPERTIES_ERROR_MALLOC_WHILE_PACKING = 5; +const Uint32 E_PROPERTIES_INVALID_VERSION_WHILE_UNPACKING = 6; +const Uint32 E_PROPERTIES_INVALID_BUFFER_TO_SHORT = 7; +const Uint32 E_PROPERTIES_ERROR_MALLOC_WHILE_UNPACKING = 8; +const Uint32 E_PROPERTIES_INVALID_CHECKSUM = 9; +const Uint32 E_PROPERTIES_BUFFER_TO_SMALL_WHILE_UNPACKING = 10; + +/** + * These are methods that used to be inline + * + * But Diab 4.1f could not compile -release with to many inlines + */ +void +Properties::setErrno(Uint32 pErr, Uint32 osErr) const { + if(parent != 0){ + parent->setErrno(pErr, osErr); + return ; + } + + /** + * propErrno & osErrno used to be mutable, + * but diab didn't know what mutable meant. + */ + *((Uint32*)&propErrno) = pErr; + *((Uint32*)&osErrno) = osErr; +} + +/** + * Inlined get/put(name, no, ...) - methods + */ + +bool +Properties::put(const char * name, Uint32 no, Uint32 val, bool replace){ + size_t tmp_len = strlen(name)+20; + char * tmp = (char*)malloc(tmp_len); + BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no); + bool res = put(tmp, val, replace); + free(tmp); + return res; +} + +bool +Properties::put64(const char * name, Uint32 no, Uint64 val, bool replace){ + size_t tmp_len = strlen(name)+20; + char * tmp = (char*)malloc(tmp_len); + BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no); + bool res = put(tmp, val, replace); + free(tmp); + return res; +} + + +bool +Properties::put(const char * name, Uint32 no, const char * val, bool replace){ + size_t tmp_len = strlen(name)+20; + char * tmp = (char*)malloc(tmp_len); + BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no); + bool res = put(tmp, val, replace); + free(tmp); + return res; +} + + +bool +Properties::put(const char * name, Uint32 no, const Properties * val, + bool replace){ + size_t tmp_len = strlen(name)+20; + char * tmp = (char*)malloc(tmp_len); + BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no); + bool res = put(tmp, val, replace); + free(tmp); + return res; +} + + +bool +Properties::getTypeOf(const char * name, Uint32 no, + PropertiesType * type) const { + size_t tmp_len = strlen(name)+20; + char * tmp = (char*)malloc(tmp_len); + BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no); + bool res = getTypeOf(tmp, type); + free(tmp); + return res; +} + +bool +Properties::contains(const char * name, Uint32 no) const { + size_t tmp_len = strlen(name)+20; + char * tmp = (char*)malloc(tmp_len); + BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no); + bool res = contains(tmp); + free(tmp); + return res; +} + +bool +Properties::get(const char * name, Uint32 no, Uint32 * value) const{ + size_t tmp_len = strlen(name)+20; + char * tmp = (char*)malloc(tmp_len); + BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no); + bool res = get(tmp, value); + free(tmp); + return res; +} + +bool +Properties::get(const char * name, Uint32 no, Uint64 * value) const{ + size_t tmp_len = strlen(name)+20; + char * tmp = (char*)malloc(tmp_len); + BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no); + bool res = get(tmp, value); + free(tmp); + return res; +} + + +bool +Properties::get(const char * name, Uint32 no, const char ** value) const { + size_t tmp_len = strlen(name)+20; + char * tmp = (char*)malloc(tmp_len); + BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no); + bool res = get(tmp, value); + free(tmp); + return res; +} + + +bool +Properties::get(const char * name, Uint32 no, const Properties ** value) const{ + size_t tmp_len = strlen(name)+20; + char * tmp = (char*)malloc(tmp_len); + BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no); + bool res = get(tmp, value); + free(tmp); + return res; +} + + +bool +Properties::getCopy(const char * name, Uint32 no, char ** value) const { + size_t tmp_len = strlen(name)+20; + char * tmp = (char*)malloc(tmp_len); + BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no); + bool res = getCopy(tmp, value); + free(tmp); + return res; +} + + +bool +Properties::getCopy(const char * name, Uint32 no, Properties ** value) const { + size_t tmp_len = strlen(name)+20; + char * tmp = (char*)malloc(tmp_len); + BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no); + bool res = getCopy(tmp, value); + free(tmp); + return res; +} + +void +Properties::setCaseInsensitiveNames(bool value){ + impl->setCaseInsensitiveNames(value); +} + +bool +Properties::getCaseInsensitiveNames() const { + return impl->m_insensitive; +} + +template bool put(PropertiesImpl *, const char *, Uint32, bool); +template bool put(PropertiesImpl *, const char *, Uint64, bool); +template bool put(PropertiesImpl *, const char *, const char *, bool); +template bool put(PropertiesImpl *, const char *, const Properties*, bool); diff --git a/storage/ndb/src/common/util/SimpleProperties.cpp b/storage/ndb/src/common/util/SimpleProperties.cpp new file mode 100644 index 00000000000..00c440fcb4e --- /dev/null +++ b/storage/ndb/src/common/util/SimpleProperties.cpp @@ -0,0 +1,507 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <ndb_global.h> +#include <SimpleProperties.hpp> +#include <NdbOut.hpp> +#include <NdbTCP.h> +#include <UtilBuffer.hpp> + +bool +SimpleProperties::Writer::first(){ + return reset(); +} + +bool +SimpleProperties::Writer::add(Uint16 key, Uint32 value){ + Uint32 head = Uint32Value; + head <<= 16; + head += key; + if(!putWord(htonl(head))) + return false; + + return putWord(htonl(value)); +} + +bool +SimpleProperties::Writer::add(Uint16 key, const char * value){ + Uint32 head = StringValue; + head <<= 16; + head += key; + if(!putWord(htonl(head))) + return false; + Uint32 strLen = strlen(value) + 1; // Including NULL-byte + if(!putWord(htonl(strLen))) + return false; + + const Uint32 valLen = (strLen + 3) / 4; + return putWords((Uint32*)value, valLen); +} + +bool +SimpleProperties::Writer::add(Uint16 key, const void* value, int len){ + Uint32 head = BinaryValue; + head <<= 16; + head += key; + if(!putWord(htonl(head))) + return false; + if(!putWord(htonl(len))) + return false; + + const Uint32 valLen = (len + 3) / 4; + return putWords((Uint32*)value, valLen); +} + +SimpleProperties::Reader::Reader(){ + m_itemLen = 0; +} + +bool +SimpleProperties::Reader::first(){ + reset(); + m_itemLen = 0; + return readValue(); +} + +bool +SimpleProperties::Reader::next(){ + return readValue(); +} + +bool +SimpleProperties::Reader::valid() const { + return m_type != InvalidValue; +} + +Uint16 +SimpleProperties::Reader::getKey() const{ + return m_key; +} + +Uint16 +SimpleProperties::Reader::getValueLen() const { + switch(m_type){ + case Uint32Value: + return 4; + case StringValue: + case BinaryValue: + return m_strLen; + case InvalidValue: + return 0; + } + return 0; +} + +SimpleProperties::ValueType +SimpleProperties::Reader::getValueType() const { + return m_type; +} + +Uint32 +SimpleProperties::Reader::getUint32() const { + return m_ui32_value; +} + +char * +SimpleProperties::Reader::getString(char * dst) const { + if(peekWords((Uint32*)dst, m_itemLen)) + return dst; + return 0; +} + +bool +SimpleProperties::Reader::readValue(){ + if(!step(m_itemLen)){ + m_type = InvalidValue; + return false; + } + + Uint32 tmp; + if(!getWord(&tmp)){ + m_type = InvalidValue; + return false; + } + + tmp = ntohl(tmp); + m_key = tmp & 0xFFFF; + m_type = (SimpleProperties::ValueType)(tmp >> 16); + switch(m_type){ + case Uint32Value: + m_itemLen = 1; + if(!peekWord(&m_ui32_value)) + return false; + m_ui32_value = ntohl(m_ui32_value); + return true; + case StringValue: + case BinaryValue: + if(!getWord(&tmp)) + return false; + m_strLen = ntohl(tmp); + m_itemLen = (m_strLen + 3)/4; + return true; + default: + m_itemLen = 0; + m_type = InvalidValue; + return false; + } +} + +SimpleProperties::UnpackStatus +SimpleProperties::unpack(Reader & it, void * dst, + const SP2StructMapping _map[], Uint32 mapSz, + bool ignoreMinMax, + bool ignoreUnknownKeys){ + do { + if(!it.valid()) + break; + + bool found = false; + Uint16 key = it.getKey(); + for(Uint32 i = 0; i<mapSz; i++){ + if(key == _map[i].Key){ + found = true; + if(_map[i].Type == InvalidValue) + return Break; + if(_map[i].Type != it.getValueType()) + return TypeMismatch; + + char * _dst = (char *)dst; + _dst += _map[i].Offset; + + switch(it.getValueType()){ + case Uint32Value:{ + const Uint32 val = it.getUint32(); + if(!ignoreMinMax){ + if(val < _map[i].minValue) + return ValueTooLow; + if(val > _map[i].maxValue) + return ValueTooHigh; + } + * ((Uint32 *)_dst) = val; + break; + } + case BinaryValue: + case StringValue:{ + unsigned len = it.getValueLen(); + if(len < _map[i].minValue) + return ValueTooLow; + if(len > _map[i].maxValue) + return ValueTooHigh; + it.getString(_dst); + break; + } + default: + abort(); + } + break; + } + } + if(!found && !ignoreUnknownKeys) + return UnknownKey; + } while(it.next()); + + return Eof; +} + +SimpleProperties::UnpackStatus +SimpleProperties::pack(Writer & it, const void * __src, + const SP2StructMapping _map[], Uint32 mapSz, + bool ignoreMinMax){ + + const char * _src = (const char *)__src; + + for(Uint32 i = 0; i<mapSz; i++){ + bool ok = false; + const char * src = _src + _map[i].Offset; + switch(_map[i].Type){ + case SimpleProperties::InvalidValue: + ok = true; + break; + case SimpleProperties::Uint32Value:{ + Uint32 val = * ((Uint32*)src); + if(!ignoreMinMax){ + if(val < _map[i].minValue) + return ValueTooLow; + if(val > _map[i].maxValue) + return ValueTooHigh; + } + ok = it.add(_map[i].Key, val); + } + break; + case SimpleProperties::BinaryValue:{ + const char * src_len = _src + _map[i].Length_Offset; + Uint32 len = *((Uint32*)src_len); + if(!ignoreMinMax){ + if(len == _map[i].maxValue) + return ValueTooHigh; + } + ok = it.add(_map[i].Key, src, len); + break; + } + case SimpleProperties::StringValue: + if(!ignoreMinMax){ + size_t len = strlen(src); + if(len == _map[i].maxValue) + return ValueTooHigh; + } + ok = it.add(_map[i].Key, src); + break; + } + if(!ok) + return OutOfMemory; + } + + return Eof; +} + +void +SimpleProperties::Reader::printAll(NdbOut& ndbout){ + char tmp[1024]; + for(first(); valid(); next()){ + switch(getValueType()){ + case SimpleProperties::Uint32Value: + ndbout << "Key: " << getKey() + << " value(" << getValueLen() << ") : " + << getUint32() << endl; + break; + case SimpleProperties::BinaryValue: + case SimpleProperties::StringValue: + if(getValueLen() < 1024){ + getString(tmp); + ndbout << "Key: " << getKey() + << " value(" << getValueLen() << ") : " + << "\"" << tmp << "\"" << endl; + } else { + ndbout << "Key: " << getKey() + << " value(" << getValueLen() << ") : " + << "\"" << "<TOO LONG>" << "\"" << endl; + + } + break; + default: + ndbout << "Unknown type for key: " << getKey() + << " type: " << (Uint32)getValueType() << endl; + } + } +} + +SimplePropertiesLinearReader::SimplePropertiesLinearReader +(const Uint32 * src, Uint32 len){ + m_src = src; + m_len = len; + m_pos = 0; + first(); +} + +void +SimplePropertiesLinearReader::reset() { + m_pos = 0; +} + +bool +SimplePropertiesLinearReader::step(Uint32 len){ + m_pos += len; + return m_pos < m_len; +} + +bool +SimplePropertiesLinearReader::getWord(Uint32 * dst) { + if(m_pos<m_len){ + * dst = m_src[m_pos++]; + return true; + } + return false; +} + +bool +SimplePropertiesLinearReader::peekWord(Uint32 * dst) const { + if(m_pos<m_len){ + * dst = m_src[m_pos]; + return true; + } + return false; +} + +bool +SimplePropertiesLinearReader::peekWords(Uint32 * dst, Uint32 len) const { + if(m_pos + len <= m_len){ + memcpy(dst, &m_src[m_pos], 4 * len); + return true; + } + return false; +} + +LinearWriter::LinearWriter(Uint32 * src, Uint32 len){ + m_src = src; + m_len = len; + reset(); +} + +bool LinearWriter::reset() { m_pos = 0; return m_len > 0;} + +bool +LinearWriter::putWord(Uint32 val){ + if(m_pos < m_len){ + m_src[m_pos++] = val; + return true; + } + return false; +} + +bool +LinearWriter::putWords(const Uint32 * src, Uint32 len){ + if(m_pos + len <= m_len){ + memcpy(&m_src[m_pos], src, 4 * len); + m_pos += len; + return true; + } + return false; +} + +Uint32 +LinearWriter::getWordsUsed() const { return m_pos;} + +UtilBufferWriter::UtilBufferWriter(UtilBuffer & b) + : m_buf(b) +{ + reset(); +} + +bool UtilBufferWriter::reset() { m_buf.clear(); return true;} + +bool +UtilBufferWriter::putWord(Uint32 val){ + return (m_buf.append(&val, 4) == 0); +} + +bool +UtilBufferWriter::putWords(const Uint32 * src, Uint32 len){ + return (m_buf.append(src, 4 * len) == 0); +} + +Uint32 +UtilBufferWriter::getWordsUsed() const { return m_buf.length() / 4;} + +#if 0 +LinearPagesReader::LinearPagesReader(const Uint32 * base, + Uint32 pageSize, + Uint32 headerSize, + Uint32 noOfPages, + Uint32 len){ + m_base = base; + m_pageSz = pageSize; + m_noOfPages = noOfPages; + m_pageHeaderSz = headerSize; + m_len = len; + reset(); +} + +void +LinearPagesReader::reset() { m_pos = 0;} + +bool +LinearPagesReader::step(Uint32 len){ + m_pos += len; + return m_pos < m_len; +} + +bool +LinearPagesReader::getWord(Uint32 * dst) { + if(m_pos<m_len){ + * dst = m_base[getPos(m_pos++)]; + return true; + } + return false; +} + +bool +LinearPagesReader::peekWord(Uint32 * dst) const { + if(m_pos<m_len){ + * dst = m_base[getPos(m_pos)]; + return true; + } + return false; +} + +bool +LinearPagesReader::peekWords(Uint32 * dst, Uint32 len) const { + if(m_pos + len <= m_len){ + for(Uint32 i = 0; i<len; i++) + * (dst + i) = m_base[getPos(m_pos + i)]; + return true; + } + return false; +} + +Uint32 +LinearPagesReader::getPos(Uint32 pos) const { + const Uint32 sz = (m_pageSz - m_pageHeaderSz); + Uint32 no = pos / sz; + Uint32 in = pos % sz; + return no * m_pageSz + m_pageHeaderSz + in; +} + +LinearPagesWriter::LinearPagesWriter(Uint32 * base, + Uint32 pageSize, + Uint32 noOfPages, + Uint32 headerSize){ + m_base = base; + m_pageSz = pageSize; + m_noOfPages = noOfPages; + m_pageHeaderSz = headerSize; + m_len = noOfPages * (pageSize - headerSize); + reset(); +} + +bool +LinearPagesWriter::putWord(Uint32 val){ + if(m_pos < m_len){ + m_base[getPos(m_pos++)] = val; + return true; + } + return false; +} + +bool +LinearPagesWriter::putWords(const Uint32 * src, Uint32 len){ + if(m_pos + len <= m_len){ + for(Uint32 i = 0; i<len; i++) + m_base[getPos(m_pos++)] = src[i]; + return true; + } + return false; +} + +#if 0 +Uint32 +LinearPagesWriter::getWordsUsed() const { + return getPos(m_pos); +} +#endif + +Uint32 +LinearPagesWriter::getPagesUsed() const { + return m_pos / (m_pageSz - m_pageHeaderSz); +} + +Uint32 +LinearPagesWriter::getPos(Uint32 pos) const { + const Uint32 sz = (m_pageSz - m_pageHeaderSz); + Uint32 no = pos / sz; + Uint32 in = pos % sz; + return no * m_pageSz + m_pageHeaderSz + in; +} +#endif diff --git a/storage/ndb/src/common/util/SocketAuthenticator.cpp b/storage/ndb/src/common/util/SocketAuthenticator.cpp new file mode 100644 index 00000000000..aed4db39231 --- /dev/null +++ b/storage/ndb/src/common/util/SocketAuthenticator.cpp @@ -0,0 +1,91 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +#include <ndb_global.h> + +#include <SocketClient.hpp> +#include <SocketAuthenticator.hpp> +#include <InputStream.hpp> +#include <OutputStream.hpp> +#include <NdbOut.hpp> + +SocketAuthSimple::SocketAuthSimple(const char *username, const char *passwd) { + if (username) + m_username= strdup(username); + else + m_username= 0; + if (passwd) + m_passwd= strdup(passwd); + else + m_passwd= 0; +} + +SocketAuthSimple::~SocketAuthSimple() +{ + if (m_passwd) + free((void*)m_passwd); + if (m_username) + free((void*)m_username); +} + +bool SocketAuthSimple::client_authenticate(int sockfd) +{ + SocketOutputStream s_output(sockfd); + SocketInputStream s_input(sockfd); + + if (m_username) + s_output.println("%s", m_username); + else + s_output.println(""); + + if (m_passwd) + s_output.println("%s", m_passwd); + else + s_output.println(""); + + char buf[16]; + if (s_input.gets(buf, 16) == 0) return false; + if (strncmp("ok", buf, 2) == 0) + return true; + + return false; +} + +bool SocketAuthSimple::server_authenticate(int sockfd) +{ + + SocketOutputStream s_output(sockfd); + SocketInputStream s_input(sockfd); + + char buf[256]; + + if (s_input.gets(buf, 256) == 0) return false; + buf[255]= 0; + if (m_username) + free((void*)m_username); + m_username= strdup(buf); + + if (s_input.gets(buf, 256) == 0) return false; + buf[255]= 0; + if (m_passwd) + free((void*)m_passwd); + m_passwd= strdup(buf); + + s_output.println("ok"); + + return true; +} diff --git a/storage/ndb/src/common/util/SocketClient.cpp b/storage/ndb/src/common/util/SocketClient.cpp new file mode 100644 index 00000000000..38df1417eb8 --- /dev/null +++ b/storage/ndb/src/common/util/SocketClient.cpp @@ -0,0 +1,94 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +#include <ndb_global.h> +#include <NdbOut.hpp> + +#include <SocketClient.hpp> +#include <SocketAuthenticator.hpp> + +SocketClient::SocketClient(const char *server_name, unsigned short port, SocketAuthenticator *sa) +{ + m_auth= sa; + m_port= port; + m_server_name= strdup(server_name); + m_sockfd= NDB_INVALID_SOCKET; +} + +SocketClient::~SocketClient() +{ + if (m_server_name) + free(m_server_name); + if (m_sockfd != NDB_INVALID_SOCKET) + NDB_CLOSE_SOCKET(m_sockfd); + if (m_auth) + delete m_auth; +} + +bool +SocketClient::init() +{ + if (m_sockfd != NDB_INVALID_SOCKET) + NDB_CLOSE_SOCKET(m_sockfd); + + memset(&m_servaddr, 0, sizeof(m_servaddr)); + m_servaddr.sin_family = AF_INET; + m_servaddr.sin_port = htons(m_port); + // Convert ip address presentation format to numeric format + if (Ndb_getInAddr(&m_servaddr.sin_addr, m_server_name)) + return false; + + m_sockfd= socket(AF_INET, SOCK_STREAM, 0); + if (m_sockfd == NDB_INVALID_SOCKET) { + return false; + } + + return true; +} + +NDB_SOCKET_TYPE +SocketClient::connect() +{ + if (m_sockfd == NDB_INVALID_SOCKET) + { + if (!init()) { +#ifdef VM_TRACE + ndbout << "SocketClient::connect() failed " << m_server_name << " " << m_port << endl; +#endif + return NDB_INVALID_SOCKET; + } + } + const int r = ::connect(m_sockfd, (struct sockaddr*) &m_servaddr, sizeof(m_servaddr)); + if (r == -1) { + NDB_CLOSE_SOCKET(m_sockfd); + m_sockfd= NDB_INVALID_SOCKET; + return NDB_INVALID_SOCKET; + } + + if (m_auth) { + if (!m_auth->client_authenticate(m_sockfd)) + { + NDB_CLOSE_SOCKET(m_sockfd); + m_sockfd= NDB_INVALID_SOCKET; + return NDB_INVALID_SOCKET; + } + } + NDB_SOCKET_TYPE sockfd= m_sockfd; + m_sockfd= NDB_INVALID_SOCKET; + + return sockfd; +} diff --git a/storage/ndb/src/common/util/SocketServer.cpp b/storage/ndb/src/common/util/SocketServer.cpp new file mode 100644 index 00000000000..6019d24d736 --- /dev/null +++ b/storage/ndb/src/common/util/SocketServer.cpp @@ -0,0 +1,345 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +#include <ndb_global.h> +#include <my_pthread.h> + +#include <SocketServer.hpp> + +#include <NdbTCP.h> +#include <NdbOut.hpp> +#include <NdbThread.h> +#include <NdbSleep.h> + +#define DEBUG(x) ndbout << x << endl; + +SocketServer::SocketServer(int maxSessions) : + m_sessions(10), + m_services(5) +{ + m_thread = 0; + m_stopThread = false; + m_maxSessions = maxSessions; +} + +SocketServer::~SocketServer() { + unsigned i; + for(i = 0; i<m_sessions.size(); i++){ + delete m_sessions[i].m_session; + } + for(i = 0; i<m_services.size(); i++){ + delete m_services[i].m_service; + } +} + +bool +SocketServer::tryBind(unsigned short port, const char * intface) { + struct sockaddr_in servaddr; + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = htonl(INADDR_ANY); + servaddr.sin_port = htons(port); + + if(intface != 0){ + if(Ndb_getInAddr(&servaddr.sin_addr, intface)) + return false; + } + + const NDB_SOCKET_TYPE sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock == NDB_INVALID_SOCKET) { + return false; + } + + const int on = 1; + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, + (const char*)&on, sizeof(on)) == -1) { + NDB_CLOSE_SOCKET(sock); + return false; + } + + if (bind(sock, (struct sockaddr*) &servaddr, sizeof(servaddr)) == -1) { + NDB_CLOSE_SOCKET(sock); + return false; + } + + NDB_CLOSE_SOCKET(sock); + return true; +} + +bool +SocketServer::setup(SocketServer::Service * service, + unsigned short * port, + const char * intface){ + DBUG_ENTER("SocketServer::setup"); + DBUG_PRINT("enter",("interface=%s, port=%u", intface, *port)); + struct sockaddr_in servaddr; + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = htonl(INADDR_ANY); + servaddr.sin_port = htons(*port); + + if(intface != 0){ + if(Ndb_getInAddr(&servaddr.sin_addr, intface)) + DBUG_RETURN(false); + } + + const NDB_SOCKET_TYPE sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock == NDB_INVALID_SOCKET) { + DBUG_PRINT("error",("socket() - %d - %s", + errno, strerror(errno))); + DBUG_RETURN(false); + } + + const int on = 1; + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, + (const char*)&on, sizeof(on)) == -1) { + DBUG_PRINT("error",("getsockopt() - %d - %s", + errno, strerror(errno))); + NDB_CLOSE_SOCKET(sock); + DBUG_RETURN(false); + } + + if (bind(sock, (struct sockaddr*) &servaddr, sizeof(servaddr)) == -1) { + DBUG_PRINT("error",("bind() - %d - %s", + errno, strerror(errno))); + NDB_CLOSE_SOCKET(sock); + DBUG_RETURN(false); + } + + /* Get the port we bound to */ + SOCKET_SIZE_TYPE sock_len = sizeof(servaddr); + if(getsockname(sock,(struct sockaddr*)&servaddr,&sock_len)<0) { + ndbout_c("An error occurred while trying to find out what" + " port we bound to. Error: %s",strerror(errno)); + NDB_CLOSE_SOCKET(sock); + DBUG_RETURN(false); + } + + DBUG_PRINT("info",("bound to %u",ntohs(servaddr.sin_port))); + if (listen(sock, m_maxSessions) == -1){ + DBUG_PRINT("error",("listen() - %d - %s", + errno, strerror(errno))); + NDB_CLOSE_SOCKET(sock); + DBUG_RETURN(false); + } + + ServiceInstance i; + i.m_socket = sock; + i.m_service = service; + m_services.push_back(i); + + *port = ntohs(servaddr.sin_port); + + DBUG_RETURN(true); +} + +void +SocketServer::doAccept(){ + fd_set readSet, exceptionSet; + FD_ZERO(&readSet); + FD_ZERO(&exceptionSet); + + m_services.lock(); + int maxSock = 0; + for (unsigned i = 0; i < m_services.size(); i++){ + const NDB_SOCKET_TYPE s = m_services[i].m_socket; + FD_SET(s, &readSet); + FD_SET(s, &exceptionSet); + maxSock = (maxSock > s ? maxSock : s); + } + struct timeval timeout; + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + if(select(maxSock + 1, &readSet, 0, &exceptionSet, &timeout) > 0){ + for (unsigned i = 0; i < m_services.size(); i++){ + ServiceInstance & si = m_services[i]; + + if(FD_ISSET(si.m_socket, &readSet)){ + NDB_SOCKET_TYPE childSock = accept(si.m_socket, 0, 0); + if(childSock == NDB_INVALID_SOCKET){ + continue; + } + + SessionInstance s; + s.m_service = si.m_service; + s.m_session = si.m_service->newSession(childSock); + if(s.m_session != 0){ + m_sessions.push_back(s); + startSession(m_sessions.back()); + } + + continue; + } + + if(FD_ISSET(si.m_socket, &exceptionSet)){ + DEBUG("socket in the exceptionSet"); + continue; + } + } + } + m_services.unlock(); +} + +extern "C" +void* +socketServerThread_C(void* _ss){ + SocketServer * ss = (SocketServer *)_ss; + ss->doRun(); + return 0; +} + +void +SocketServer::startServer(){ + m_threadLock.lock(); + if(m_thread == 0 && m_stopThread == false){ + m_thread = NdbThread_Create(socketServerThread_C, + (void**)this, + 32768, + "NdbSockServ", + NDB_THREAD_PRIO_LOW); + } + m_threadLock.unlock(); +} + +void +SocketServer::stopServer(){ + m_threadLock.lock(); + if(m_thread != 0){ + m_stopThread = true; + + void * res; + NdbThread_WaitFor(m_thread, &res); + NdbThread_Destroy(&m_thread); + m_thread = 0; + } + m_threadLock.unlock(); +} + +void +SocketServer::doRun(){ + + while(!m_stopThread){ + checkSessions(); + if(m_sessions.size() < m_maxSessions){ + doAccept(); + } else { + NdbSleep_MilliSleep(200); + } + } +} + +void +SocketServer::startSession(SessionInstance & si){ + si.m_thread = NdbThread_Create(sessionThread_C, + (void**)si.m_session, + 32768, + "NdbSock_Session", + NDB_THREAD_PRIO_LOW); +} + +static +bool +transfer(NDB_SOCKET_TYPE sock){ +#if defined NDB_OSE || defined NDB_SOFTOSE + const PROCESS p = current_process(); + const size_t ps = sizeof(PROCESS); + int res = setsockopt(sock, SOL_SOCKET, SO_OSEOWNER, &p, ps); + if(res != 0){ + ndbout << "Failed to transfer ownership of socket" << endl; + return false; + } +#endif + return true; +} + +void +SocketServer::foreachSession(void (*func)(SocketServer::Session*, void *), void *data) +{ + for(int i = m_sessions.size() - 1; i >= 0; i--){ + (*func)(m_sessions[i].m_session, data); + } + checkSessions(); +} + +void +SocketServer::checkSessions(){ + for(int i = m_sessions.size() - 1; i >= 0; i--){ + if(m_sessions[i].m_session->m_stopped){ + if(m_sessions[i].m_thread != 0){ + void* ret; + NdbThread_WaitFor(m_sessions[i].m_thread, &ret); + NdbThread_Destroy(&m_sessions[i].m_thread); + } + m_sessions[i].m_session->stopSession(); + delete m_sessions[i].m_session; + m_sessions.erase(i); + } + } +} + +void +SocketServer::stopSessions(bool wait){ + int i; + for(i = m_sessions.size() - 1; i>=0; i--) + { + m_sessions[i].m_session->stopSession(); + m_sessions[i].m_session->m_stop = true; // to make sure + } + for(i = m_services.size() - 1; i>=0; i--) + m_services[i].m_service->stopSessions(); + + if(wait){ + while(m_sessions.size() > 0){ + checkSessions(); + NdbSleep_MilliSleep(100); + } + } +} + +/***** Session code ******/ + +extern "C" +void* +sessionThread_C(void* _sc){ + SocketServer::Session * si = (SocketServer::Session *)_sc; + + if(!transfer(si->m_socket)){ + si->m_stopped = true; + return 0; + } + + /** + * may have m_stopped set if we're transforming a mgm + * connection into a transporter connection. + */ + if(!si->m_stopped) + { + if(!si->m_stop){ + si->m_stopped = false; + si->runSession(); + } else { + NDB_CLOSE_SOCKET(si->m_socket); + } + } + + si->m_stopped = true; + return 0; +} + +template class MutexVector<SocketServer::ServiceInstance>; +template class MutexVector<SocketServer::SessionInstance>; diff --git a/storage/ndb/src/common/util/basestring_vsnprintf.c b/storage/ndb/src/common/util/basestring_vsnprintf.c new file mode 100644 index 00000000000..f5d01fb1532 --- /dev/null +++ b/storage/ndb/src/common/util/basestring_vsnprintf.c @@ -0,0 +1,71 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifdef __sgi +/* define on IRIX to get posix compliant vsnprintf */ +#define _XOPEN_SOURCE 500 +#endif +#include <stdio.h> +#include <basestring_vsnprintf.h> +#include <my_config.h> + +#ifdef _WINDOWS +#define SNPRINTF_RETURN_TRUNC +#define snprintf _snprintf +#define vsnprintf _vsnprintf +#endif + +int +basestring_snprintf(char *str, size_t size, const char *format, ...) +{ + int ret; + va_list ap; + va_start(ap, format); + ret= basestring_vsnprintf(str, size, format, ap); + va_end(ap); + return(ret); +} + +#ifdef SNPRINTF_RETURN_TRUNC +static char basestring_vsnprintf_buf[16*1024]; +#endif +int +basestring_vsnprintf(char *str, size_t size, const char *format, va_list ap) +{ + if (size == 0) + { +#ifdef SNPRINTF_RETURN_TRUNC + return vsnprintf(basestring_vsnprintf_buf, + sizeof(basestring_vsnprintf_buf), + format, ap); +#else + char buf[1]; + return vsnprintf(buf, 1, format, ap); +#endif + } + { + int ret= vsnprintf(str, size, format, ap); +#ifdef SNPRINTF_RETURN_TRUNC + if (ret == size-1 || ret == -1) + { + ret= vsnprintf(basestring_vsnprintf_buf, + sizeof(basestring_vsnprintf_buf), + format, ap); + } +#endif + return ret; + } +} diff --git a/storage/ndb/src/common/util/filetest/FileUnitTest.cpp b/storage/ndb/src/common/util/filetest/FileUnitTest.cpp new file mode 100644 index 00000000000..b6e7b7e8ec0 --- /dev/null +++ b/storage/ndb/src/common/util/filetest/FileUnitTest.cpp @@ -0,0 +1,237 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include "FileUnitTest.hpp" +#include <File.hpp> + +#include <NdbOut.hpp> + +typedef bool (*TESTFUNC)(const char*); + +typedef const char TESTNAME; +typedef struct +{ + const char* name; + TESTFUNC test; +}Tests; + +static Tests testCases[] = { {"Create/Write", &FileUnitTest::testWrite}, + {"Read", &FileUnitTest::testRead}, + {"Exists", &FileUnitTest::testExists}, + {"File Size", &FileUnitTest::testSize}, + {"Rename", &FileUnitTest::testRename}, + {"Remove", &FileUnitTest::testRemove} }; + +static int testFailed = 0; + +int main(int argc, char* argv[]) +{ + if (argc < 2) + { + ndbout << "Usage: filetest <filename>" << endl; + return 0; + } + const char* fileName = argv[1]; + + int testCount = (sizeof(testCases) / sizeof(Tests)); + ndbout << "Starting " << testCount << " tests..." << endl; + for (int i = 0; i < testCount; i++) + { + ndbout << "-- " << " Test " << i + 1 + << " [" << testCases[i].name << "] --" << endl; + if (testCases[i].test(fileName)) + { + ndbout << "-- Passed --" << endl; + } + else + { + ndbout << "-- Failed -- " << endl; + } + + } + ndbout << endl << "-- " << testCount - testFailed << " passed, " + << testFailed << " failed --" << endl; + return 0; +} + + +bool +FileUnitTest::testWrite(const char* aFileName) +{ + bool rc = true; + File f; + if (f.open(aFileName, "w")) + { + f.writeChar("ABABABABABAB ABBABAB ABBABA ABAB JKH KJHA JHHAHAH..."); + f.writeChar("12129791242 1298371923 912738912 378129837128371128132...\n"); + f.close(); + } + else + { + error("testWrite failed: "); + rc = false; + } + return rc; +} + +bool +FileUnitTest::testRead(const char* aFileName) +{ + bool rc = true; + // Read file + File f; + if (f.open(aFileName, "r")) + { + long size = f.size(); + ndbout << "File size = " << size << endl; + ndbout << "Allocating buf of " << size << " bytes" << endl; + char* buf = new char[size]; + buf[size - 1] = '\0'; + int r = 0; + while ((r = f.readChar(buf, r, size)) > 0) + { + ndbout << "Read(" << r << "):" << buf << endl; + } + f.close(); + delete buf; + } + else + { + error("readTest failed: "); + rc = false; + } + return rc; +} + +bool +FileUnitTest::testExists(const char* aFileName) +{ + bool rc = true; + if (File::exists(aFileName)) + { + if (File::exists("ThisFileShouldnotbe.txt")) + { + rc = false; + error("testExists failed, the file should NOT be found."); + } + } + else + { + rc = false; + error("testExists failed, the file should exist."); + } + + return rc; +} + + +bool +FileUnitTest::testSize(const char* aFileName) +{ + bool rc = true; + File f; + if (f.open(aFileName, "r")) + { + long size = f.size(); + if (size <= 0) + { + rc = false; + error("testSize failed, size is <= 0"); + } + ndbout << "File size = " << size << endl; + } + else + { + rc = false; + error("testSize failed, could no open file."); + } + f.close(); + return rc; +} + +bool +FileUnitTest::testRename(const char* aFileName) +{ + bool rc = true; + if (File::rename(aFileName, "filetest_new.txt")) + { + if (!File::exists("filetest_new.txt")) + { + rc = false; + error("testRename failed, new file does not exists."); + } + else + { + ndbout << "Renamed " << aFileName << " to filetest_new.txt" << endl; + } + } + else + { + rc = false; + error("testRename failed, unable to rename file."); + } + + return rc; +} + +bool +FileUnitTest::testRemove(const char* aFileName) +{ + bool rc = true; + File f; + if (f.open("filetest_new.txt", "r")) + { + if (!f.remove()) + { + rc = false; + error("testRemove failed, could not remove file."); + } + else + { + if (File::exists("filetest_new")) + { + rc = false; + error("testRemove failed, file was not removed, it still exists."); + } + } + } // (f.open("filetest_new", "r")) + else + { + rc = false; + error("testRemove failed, could not read the file."); + } + + return rc; +} + +void +FileUnitTest::error(const char* msg) +{ + testFailed++; + ndbout << "Test failed: " << msg << endl; + perror("Errno msg"); +} + + +FileUnitTest::FileUnitTest() +{ + +} + +FileUnitTest::~FileUnitTest() +{ + +} diff --git a/storage/ndb/src/common/util/filetest/FileUnitTest.hpp b/storage/ndb/src/common/util/filetest/FileUnitTest.hpp new file mode 100644 index 00000000000..a589615e9b2 --- /dev/null +++ b/storage/ndb/src/common/util/filetest/FileUnitTest.hpp @@ -0,0 +1,41 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef FILEUNITTEST_H +#define FILEUNITTEST_H + +/** + * Unit test of File. + * + * @version #@ $Id: FileUnitTest.hpp,v 1.1 2002/03/13 18:09:03 eyualex Exp $ + */ +class FileUnitTest +{ +public: + static bool testWrite(const char* aFileName); + static bool testRead(const char* aFileName); + static bool testExists(const char* aFileName); + static bool testSize(const char* aFileName); + static bool testRename(const char* aFileName); + static bool testRemove(const char* aFileName); + + static void error(const char* msg); +private: + FileUnitTest(); + ~FileUnitTest(); + +}; +#endif diff --git a/storage/ndb/src/common/util/filetest/Makefile b/storage/ndb/src/common/util/filetest/Makefile new file mode 100644 index 00000000000..fe1842921f9 --- /dev/null +++ b/storage/ndb/src/common/util/filetest/Makefile @@ -0,0 +1,14 @@ +include .defs.mk + +TYPE := + +BIN_TARGET := filetest +BIN_TARGET_ARCHIVES := portlib general + +SOURCES := FileUnitTest.cpp + +CCFLAGS_LOC += -I$(NDB_TOP)/include/logger -I$(NDB_TOP)/include/portlib + +include $(NDB_TOP)/Epilogue.mk + + diff --git a/storage/ndb/src/common/util/getarg.cat3 b/storage/ndb/src/common/util/getarg.cat3 new file mode 100644 index 00000000000..31685510537 --- /dev/null +++ b/storage/ndb/src/common/util/getarg.cat3 @@ -0,0 +1,237 @@ +GETARG(3) OpenBSD Programmer's Manual GETARG(3) + +NNAAMMEE + ggeettaarrgg, aarrgg__pprriinnttuussaaggee - collect command line options + +SSYYNNOOPPSSIISS + ##iinncclluuddee <<ggeettaarrgg..hh>> + + + _i_n_t + ggeettaarrgg(_s_t_r_u_c_t _g_e_t_a_r_g_s _*_a_r_g_s, _s_i_z_e___t _n_u_m___a_r_g_s, _i_n_t _a_r_g_c, _c_h_a_r _*_*_a_r_g_v, + _i_n_t _*_o_p_t_i_n_d); + + + _v_o_i_d + aarrgg__pprriinnttuussaaggee(_s_t_r_u_c_t _g_e_t_a_r_g_s _*_a_r_g_s, _s_i_z_e___t _n_u_m___a_r_g_s, + _c_o_n_s_t _c_h_a_r _*_p_r_o_g_n_a_m_e, _c_o_n_s_t _c_h_a_r _*_e_x_t_r_a___s_t_r_i_n_g); + + +DDEESSCCRRIIPPTTIIOONN + ggeettaarrgg() collects any command line options given to a program in an easi + ly used way. aarrgg__pprriinnttuussaaggee() pretty-prints the available options, with + a short help text. + + _a_r_g_s is the option specification to use, and it's an array of _s_t_r_u_c_t + _g_e_t_a_r_g_s elements. _n_u_m___a_r_g_s is the size of _a_r_g_s (in elements). _a_r_g_c and + _a_r_g_v are the argument count and argument vector to extract option from. + _o_p_t_i_n_d is a pointer to an integer where the index to the last processed + argument is stored, it must be initialised to the first index (minus one) + to process (normally 0) before the first call. + + _a_r_g___p_r_i_n_t_u_s_a_g_e take the same _a_r_g_s and _n_u_m___a_r_g_s as getarg; _p_r_o_g_n_a_m_e _i_s _t_h_e + _n_a_m_e _o_f _t_h_e _p_r_o_g_r_a_m _(_t_o _b_e progname0 _0progname1 _1progname2 _2progname3 + _3progname4 _4progname5 _e_x_t_r_a___s_t_r_i_n_g is a string to print after the actual + options to indicate more arguments. The usefulness of this function is + realised only be people who has used programs that has help strings that + doesn't match what the code does. + + The _g_e_t_a_r_g_s struct has the following elements. + + + struct getargs{ + const char *long_name; + char short_name; + enum { arg_integer, + arg_string, + arg_flag, + arg_negative_flag, + arg_strings, + arg_double, + arg_collect + } type; + void *value; + const char *help; + const char *arg_help; + }; + + _l_o_n_g___n_a_m_e is the long name of the option, it can be NULL, if you don't + want a long name. _s_h_o_r_t___n_a_m_e is the characted to use as short option, it + can be zero. If the option has a value the _v_a_l_u_e field gets filled in + with that value interpreted as specified by the _t_y_p_e field. _h_e_l_p is a + longer help string for the option as a whole, if it's NULL the help text + for the option is omitted (but it's still displayed in the synopsis). + _a_r_g___h_e_l_p is a description of the argument, if NULL a default value will + be used, depending on the type of the option: + + + arg_integer the argument is a signed integer, and _v_a_l_u_e should + point to an _i_n_t. + + _a_r_g___s_t_r_i_n_g the argument is a string, and _v_a_l_u_e should point to a + _c_h_a_r_*. + + _a_r_g___f_l_a_g the argument is a flag, and _v_a_l_u_e should point to a + _i_n_t. It gets filled in with either zero or one, de + pending on how the option is given, the normal case + beeing one. Note that if the option isn't given, the + value isn't altered, so it should be initialised to + some useful default. + + _a_r_g___n_e_g_a_t_i_v_e___f_l_a_g this is the same as _a_r_g___f_l_a_g but it reverses the mean + ing of the flag (a given short option clears the + flag), and the synopsis of a long option is negated. + + _a_r_g___s_t_r_i_n_g_s the argument can be given multiple times, and the val + ues are collected in an array; _v_a_l_u_e should be a + pointer to a _s_t_r_u_c_t _g_e_t_a_r_g___s_t_r_i_n_g_s structure, which + holds a length and a string pointer. + + _a_r_g___d_o_u_b_l_e argument is a double precision floating point value, + and _v_a_l_u_e should point to a _d_o_u_b_l_e. + + _a_r_g___c_o_l_l_e_c_t allows more fine-grained control of the option parsing + process. _v_a_l_u_e should be a pointer to a + _g_e_t_a_r_g___c_o_l_l_e_c_t___i_n_f_o structure: + + typedef int (*getarg_collect_func)(int short_opt, + int argc, + char **argv, + int *optind, + int *optarg, + void *data); + + typedef struct getarg_collect_info { + getarg_collect_func func; + void *data; + } getarg_collect_info; + + With the _f_u_n_c member set to a function to call, and + _d_a_t_a to some application specific data. The parameters + to the collect function are: + + _s_h_o_r_t___f_l_a_g non-zero if this call is via a short option + flag, zero otherwise + + _a_r_g_c, _a_r_g_v the whole argument list + + _o_p_t_i_n_d pointer to the index in argv where the flag is + + _o_p_t_a_r_g pointer to the index in argv[*optind] where the + flag name starts + + _d_a_t_a application specific data + + You can modify _*_o_p_t_i_n_d, and _*_o_p_t_a_r_g, but to do this + correct you (more or less) have to know about the in + ner workings of getarg. + + You can skip parts of arguments by increasing _*_o_p_t_a_r_g + (you could implement the --zz_3 set of flags from ggzziipp + with this), or whole argument strings by increasing + _*_o_p_t_i_n_d (let's say you want a flag --cc _x _y _z to specify + a coordinate); if you also have to set _*_o_p_t_a_r_g to a + sane value. + + The collect function should return one of + ARG_ERR_NO_MATCH, ARG_ERR_BAD_ARG, ARG_ERR_NO_ARG on + error, zero otherwise. + + For your convenience there is a function, + ggeettaarrgg__ooppttaarrgg(), that returns the traditional argument + string, and you pass it all arguments, sans data, that + where given to the collection function. + + Don't use this more this unless you absolutely have + to. + + Option parsing is similar to what getopt uses. Short options without ar + guments can be compressed (--xxyyzz is the same as --xx --yy --zz), and short op + tions with arguments take these as either the rest of the argv-string or + as the next option (--oo_f_o_o, or --oo _f_o_o). + + Long option names are prefixed with -- (double dash), and the value with + a = (equal), ----ffoooo==_b_a_r. Long option flags can either be specified as they + are (----hheellpp), or with an (boolean parsable) option (----hheellpp==_y_e_s, + ----hheellpp==_t_r_u_e, or similar), or they can also be negated (----nnoo--hheellpp is the + same as ----hheellpp==no), and if you're really confused you can do it multiple + times (----nnoo--nnoo--hheellpp==_f_a_l_s_e, or even ----nnoo--nnoo--hheellpp==_m_a_y_b_e). + +EEXXAAMMPPLLEE + #include <stdio.h> + #include <string.h> + #include <getarg.h> + + char *source = "Ouagadougou"; + char *destination; + int weight; + int include_catalog = 1; + int help_flag; + + struct getargs args[] = { + { "source", 's', arg_string, &source, + "source of shippment", "city" }, + { "destination", 'd', arg_string, &destination, + "destination of shippment", "city" }, + { "weight", 'w', arg_integer, &weight, + "weight of shippment", "tons" }, + { "catalog", 'c', arg_negative_flag, &include_catalog, + "include product catalog" }, + { "help", 'h', arg_flag, &help_flag } + }; + + int num_args = sizeof(args) / sizeof(args[0]); /* number of elements in args */ + + const char *progname = "ship++"; + + int + main(int argc, char **argv) + { + int optind = 0; + if (getarg(args, num_args, argc, argv, &optind)) { + arg_printusage(args, num_args, progname, "stuff..."); + exit (1); + } + if (help_flag) { + arg_printusage(args, num_args, progname, "stuff..."); + exit (0); + } + if (destination == NULL) { + fprintf(stderr, "%s: must specify destination0, progname); + exit(1); + } + if (strcmp(source, destination) == 0) { + fprintf(stderr, "%s: destination must be different from source0); + exit(1); + } + /* include more stuff here ... */ + exit(2); + } + + The output help output from this program looks like this: + + $ ship++ --help + Usage: ship++ [--source=city] [-s city] [--destination=city] [-d city] + [--weight=tons] [-w tons] [--no-catalog] [-c] [--help] [-h] stuff... + -s city, --source=city source of shippment + -d city, --destination=city destination of shippment + -w tons, --weight=tons weight of shippment + -c, --no-catalog include product catalog + + +BBUUGGSS + It should be more flexible, so it would be possible to use other more + complicated option syntaxes, such as what ps(1), and tar(1), uses, or the + AFS model where you can skip the flag names as long as the options come + in the correct order. + + Options with multiple arguments should be handled better. + + Should be integreated with SL. + + It's very confusing that the struct you pass in is called getargS. + +SSEEEE AALLSSOO + getopt(3) + + ROKEN September 24, 1999 4 diff --git a/storage/ndb/src/common/util/md5_hash.cpp b/storage/ndb/src/common/util/md5_hash.cpp new file mode 100644 index 00000000000..d4eedbc40fb --- /dev/null +++ b/storage/ndb/src/common/util/md5_hash.cpp @@ -0,0 +1,239 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + + +#include "md5_hash.hpp" + +#ifdef WORDS_BIGENDIAN +#define HIGHFIRST 1 +#endif + +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * The code has been modified by Mikael Ronstroem to handle + * calculating a hash value of a key that is always a multiple + * of 4 bytes long. Word 0 of the calculated 4-word hash value + * is returned as the hash value. + */ + +#ifndef HIGHFIRST +#define byteReverse(buf, len) /* Nothing */ +#else +void byteReverse(unsigned char *buf, unsigned longs); +/* + * Note: this code is harmless on little-endian machines. + */ +void byteReverse(unsigned char *buf, unsigned longs) +{ + Uint32 t; + do { + t = (Uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(Uint32 *) buf = t; + buf += 4; + } while (--longs); +} +#endif + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void MD5Transform(Uint32 buf[4], Uint32 const in[16]) +{ + register Uint32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void md5_hash(Uint32 result[4], const Uint64* keybuf, Uint32 no_of_32_words) +{ + /** + * This is the external interface of the module + * It is assumed that keybuf is placed on 8 byte + * alignment. + */ + Uint32 i; + Uint32 buf[4]; + Uint64 transform64_buf[8]; + Uint32* transform32_buf; + Uint32 len = no_of_32_words << 2; + const Uint64* key64buf = (const Uint64*)keybuf; + const Uint32* key32buf = (const Uint32*)keybuf; + + transform32_buf = (Uint32*)&transform64_buf[0]; + buf[0] = 0x67452301; + buf[1] = 0xefcdab89; + buf[2] = 0x98badcfe; + buf[3] = 0x10325476; + + while (no_of_32_words >= 16) { + transform64_buf[0] = key64buf[0]; + transform64_buf[1] = key64buf[1]; + transform64_buf[2] = key64buf[2]; + transform64_buf[3] = key64buf[3]; + transform64_buf[4] = key64buf[4]; + transform64_buf[5] = key64buf[5]; + transform64_buf[6] = key64buf[6]; + transform64_buf[7] = key64buf[7]; + no_of_32_words -= 16; + key64buf += 8; + byteReverse((unsigned char *)transform32_buf, 16); + MD5Transform(buf, transform32_buf); + } + + key32buf = (const Uint32*)key64buf; + transform64_buf[0] = 0; + transform64_buf[1] = 0; + transform64_buf[2] = 0; + transform64_buf[3] = 0; + transform64_buf[4] = 0; + transform64_buf[5] = 0; + transform64_buf[6] = 0; + transform64_buf[7] = (Uint64)len; + + for (i = 0; i < no_of_32_words; i++) + transform32_buf[i] = key32buf[i]; + transform32_buf[no_of_32_words] = 0x80000000; + + if (no_of_32_words < 14) { + byteReverse((unsigned char *)transform32_buf, 16); + MD5Transform(buf, transform32_buf); + } else { + if (no_of_32_words == 14) + transform32_buf[15] = 0; + MD5Transform(buf, transform32_buf); + transform64_buf[0] = 0; + transform64_buf[1] = 0; + transform64_buf[2] = 0; + transform64_buf[3] = 0; + transform64_buf[4] = 0; + transform64_buf[5] = 0; + transform64_buf[6] = 0; + transform64_buf[7] = (Uint64)len; + byteReverse((unsigned char *)transform32_buf, 16); + MD5Transform(buf, transform32_buf); + } + + result[0] = buf[0]; + result[1] = buf[1]; + result[2] = buf[2]; + result[3] = buf[3]; +} + diff --git a/storage/ndb/src/common/util/ndb_init.c b/storage/ndb/src/common/util/ndb_init.c new file mode 100644 index 00000000000..f3aa734d7f9 --- /dev/null +++ b/storage/ndb/src/common/util/ndb_init.c @@ -0,0 +1,35 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <ndb_global.h> +#include <my_sys.h> + +int +ndb_init() +{ + if (my_init()) { + const char* err = "my_init() failed - exit\n"; + write(2, err, strlen(err)); + exit(1); + } + return 0; +} + +void +ndb_end(int flags) +{ + my_end(flags); +} diff --git a/storage/ndb/src/common/util/new.cpp b/storage/ndb/src/common/util/new.cpp new file mode 100644 index 00000000000..901f74bf979 --- /dev/null +++ b/storage/ndb/src/common/util/new.cpp @@ -0,0 +1,43 @@ + +#include <ndb_global.h> +#include <NdbMem.h> + +extern "C" { + void (* ndb_new_handler)() = 0; +} + +#ifdef USE_MYSYS_NEW + +void *operator new (size_t sz) +{ + void * p = NdbMem_Allocate(sz ? sz : 1); + if(p) + return p; + if(ndb_new_handler) + (* ndb_new_handler)(); + abort(); +} + +void *operator new[] (size_t sz) +{ + void * p = (void *) NdbMem_Allocate(sz ? sz : 1); + if(p) + return p; + if(ndb_new_handler) + (* ndb_new_handler)(); + abort(); +} + +void operator delete (void *ptr) +{ + if (ptr) + NdbMem_Free(ptr); +} + +void operator delete[] (void *ptr) throw () +{ + if (ptr) + NdbMem_Free(ptr); +} + +#endif // USE_MYSYS_NEW diff --git a/storage/ndb/src/common/util/random.c b/storage/ndb/src/common/util/random.c new file mode 100644 index 00000000000..21235763793 --- /dev/null +++ b/storage/ndb/src/common/util/random.c @@ -0,0 +1,284 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/*************************************************************** +* I N C L U D E D F I L E S * +***************************************************************/ + +#include <ndb_global.h> + +#include <NdbOut.hpp> + +#include <random.h> + +/*************************************************************** +* L O C A L C O N S T A N T S * +***************************************************************/ + +/*************************************************************** +* L O C A L D A T A S T R U C T U R E S * +***************************************************************/ + +typedef struct { + unsigned short int x[3]; /* Current state. */ + unsigned short int a[3]; /* Factor in congruential formula. */ + unsigned short int c; /* Additive const. in congruential formula. */ + int init; /* Flag for initializing. */ +}DRand48Data; + +/*************************************************************** +* L O C A L F U N C T I O N S * +***************************************************************/ + +static void shuffleSequence(RandomSequence *seq); + +/*************************************************************** +* L O C A L D A T A * +***************************************************************/ + +static DRand48Data dRand48Data; + +/*************************************************************** +* P U B L I C D A T A * +***************************************************************/ + + +/*************************************************************** +**************************************************************** +* L O C A L F U N C T I O N S C O D E S E C T I O N * +**************************************************************** +***************************************************************/ + +static void localRandom48Init(long int seedval, DRand48Data *buffer) +{ + /* The standards say we only have 32 bits. */ + if (sizeof (long int) > 4) + seedval &= 0xffffffffl; + +#if USHRT_MAX == 0xffffU + buffer->x[2] = seedval >> 16; + buffer->x[1] = seedval & 0xffffl; + buffer->x[0] = 0x330e; + + buffer->a[2] = 0x5; + buffer->a[1] = 0xdeec; + buffer->a[0] = 0xe66d; +#else + buffer->x[2] = seedval; + buffer->x[1] = 0x330e0000UL; + buffer->x[0] = 0; + + buffer->a[2] = 0x5deecUL; + buffer->a[1] = 0xe66d0000UL; + buffer->a[0] = 0; +#endif + + buffer->c = 0xb; + buffer->init = 1; +} + +static void localRandom48(DRand48Data *buffer, long int *result) +{ + Uint64 X; + Uint64 a; + Uint64 loc_result; + + /*--------------------------------------*/ + /* Initialize buffer, if not yet done. */ + /*--------------------------------------*/ + if (!buffer->init) { +#if (USHRT_MAX == 0xffffU) + buffer->a[2] = 0x5; + buffer->a[1] = 0xdeec; + buffer->a[0] = 0xe66d; +#else + buffer->a[2] = 0x5deecUL; + buffer->a[1] = 0xe66d0000UL; + buffer->a[0] = 0; +#endif + buffer->c = 0xb; + buffer->init = 1; + } + + /* Do the real work. We choose a data type which contains at least + 48 bits. Because we compute the modulus it does not care how + many bits really are computed. */ + + if (sizeof (unsigned short int) == 2) { + X = (Uint64)buffer->x[2] << 32 | + (Uint64)buffer->x[1] << 16 | + buffer->x[0]; + a = ((Uint64)buffer->a[2] << 32 | + (Uint64)buffer->a[1] << 16 | + buffer->a[0]); + + loc_result = X * a + buffer->c; + + buffer->x[0] = loc_result & 0xffff; + buffer->x[1] = (loc_result >> 16) & 0xffff; + buffer->x[2] = (loc_result >> 32) & 0xffff; + } + else { + X = (Uint64)buffer->x[2] << 16 | + buffer->x[1] >> 16; + a = (Uint64)buffer->a[2] << 16 | + buffer->a[1] >> 16; + + loc_result = X * a + buffer->c; + + buffer->x[0] = loc_result >> 16 & 0xffffffffl; + buffer->x[1] = loc_result << 16 & 0xffff0000l; + } + + /*--------------------*/ + /* Store the result. */ + /*--------------------*/ + if (sizeof (unsigned short int) == 2) + *result = buffer->x[2] << 15 | buffer->x[1] >> 1; + else + *result = buffer->x[2] >> 1; +} + +static void shuffleSequence(RandomSequence *seq) +{ + unsigned int i; + unsigned int j; + unsigned int tmp; + + if( !seq ) return; + + for(i = 0; i < seq->length; i++ ) { + j = myRandom48(seq->length); + if( i != j ) { + tmp = seq->values[i]; + seq->values[i] = seq->values[j]; + seq->values[j] = tmp; + } + } +} + + +/*************************************************************** +**************************************************************** +* P U B L I C F U N C T I O N S C O D E S E C T I O N * +**************************************************************** +***************************************************************/ + + +double getTps(unsigned int count, double timeValue) +{ + double f; + + if( timeValue != 0.0 ) + f = count / timeValue; + else + f = 0.0; + + return(f); +} + +/*----------------------------*/ +/* Random Sequences Functions */ +/*----------------------------*/ +int initSequence(RandomSequence *seq, SequenceValues *inputValues) +{ + unsigned int i; + unsigned int j; + unsigned int totalLength; + unsigned int index; + + if( !seq || !inputValues ) return(-1); + + /*------------------------------------*/ + /* Find the total length of the array */ + /*------------------------------------*/ + totalLength = 0; + + for(i = 0; inputValues[i].length != 0; i++) + totalLength += inputValues[i].length; + + if( totalLength == 0 ) return(-1); + + seq->length = totalLength; + seq->values = calloc(totalLength, sizeof(unsigned int)); + + if( seq->values == 0 ) return(-1); + + /*----------------------*/ + /* set the array values */ + /*----------------------*/ + index = 0; + + for(i = 0; inputValues[i].length != 0; i++) { + for(j = 0; j < inputValues[i].length; j++ ) { + seq->values[index] = inputValues[i].value; + index++; + } + } + + shuffleSequence(seq); + + seq->currentIndex = 0; + + return(0); +} + +unsigned int getNextRandom(RandomSequence *seq) +{ + unsigned int nextValue; + + nextValue = seq->values[seq->currentIndex]; + + seq->currentIndex++; + + if(seq->currentIndex == seq->length){ + seq->currentIndex = 0; + shuffleSequence(seq); + } + + return nextValue; +} + +void printSequence(RandomSequence *seq, unsigned int numPerRow) +{ + unsigned int i; + + if( !seq ) return; + + for(i = 0; i<seq->length; i++) { + ndbout_c("%d ", seq->values[i]); + + if((i+1) % numPerRow == 0) + ndbout_c(""); + } + + if(i % numPerRow != 0) + ndbout_c(""); +} + +void myRandom48Init(long int seedval) +{ + localRandom48Init(seedval, &dRand48Data); +} + +long int myRandom48(unsigned int maxValue) +{ + long int result; + + localRandom48(&dRand48Data, &result); + + return(result % maxValue); +} diff --git a/storage/ndb/src/common/util/socket_io.cpp b/storage/ndb/src/common/util/socket_io.cpp new file mode 100644 index 00000000000..83a546de773 --- /dev/null +++ b/storage/ndb/src/common/util/socket_io.cpp @@ -0,0 +1,281 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <ndb_global.h> + +#include <NdbTCP.h> +#include <socket_io.h> +#include <NdbOut.hpp> + +extern "C" +int +read_socket(NDB_SOCKET_TYPE socket, int timeout_millis, + char * buf, int buflen){ + if(buflen < 1) + return 0; + + fd_set readset; + FD_ZERO(&readset); + FD_SET(socket, &readset); + + struct timeval timeout; + timeout.tv_sec = (timeout_millis / 1000); + timeout.tv_usec = (timeout_millis % 1000) * 1000; + + const int selectRes = select(socket + 1, &readset, 0, 0, &timeout); + if(selectRes == 0) + return 0; + + if(selectRes == -1){ + return -1; + } + + return recv(socket, &buf[0], buflen, 0); +} + +extern "C" +int +readln_socket(NDB_SOCKET_TYPE socket, int timeout_millis, + char * buf, int buflen){ + if(buflen <= 1) + return 0; + + fd_set readset; + FD_ZERO(&readset); + FD_SET(socket, &readset); + + struct timeval timeout; + timeout.tv_sec = (timeout_millis / 1000); + timeout.tv_usec = (timeout_millis % 1000) * 1000; + + const int selectRes = select(socket + 1, &readset, 0, 0, &timeout); + if(selectRes == 0) + return 0; + + if(selectRes == -1){ + return -1; + } + + int pos = 0; buf[pos] = 0; + while(true){ + const int t = recv(socket, &buf[pos], 1, 0); + if(t != 1){ + return -1; + } + if(buf[pos] == '\n'){ + buf[pos] = 0; + + if(pos > 0 && buf[pos-1] == '\r'){ + pos--; + buf[pos] = 0; + } + + return pos; + } + pos++; + if(pos == (buflen - 1)){ + buf[pos] = 0; + return buflen; + } + + FD_ZERO(&readset); + FD_SET(socket, &readset); + timeout.tv_sec = (timeout_millis / 1000); + timeout.tv_usec = (timeout_millis % 1000) * 1000; + const int selectRes = select(socket + 1, &readset, 0, 0, &timeout); + if(selectRes != 1){ + return -1; + } + } +} + +extern "C" +int +write_socket(NDB_SOCKET_TYPE socket, int timeout_millis, + const char buf[], int len){ + fd_set writeset; + FD_ZERO(&writeset); + FD_SET(socket, &writeset); + struct timeval timeout; + timeout.tv_sec = (timeout_millis / 1000); + timeout.tv_usec = (timeout_millis % 1000) * 1000; + + const int selectRes = select(socket + 1, 0, &writeset, 0, &timeout); + if(selectRes != 1){ + return -1; + } + + const char * tmp = &buf[0]; + while(len > 0){ + const int w = send(socket, tmp, len, 0); + if(w == -1){ + return -1; + } + len -= w; + tmp += w; + + if(len == 0) + break; + + FD_ZERO(&writeset); + FD_SET(socket, &writeset); + timeout.tv_sec = 1; + timeout.tv_usec = 0; + const int selectRes = select(socket + 1, 0, &writeset, 0, &timeout); + if(selectRes != 1){ + return -1; + } + } + + return 0; +} + +extern "C" +int +print_socket(NDB_SOCKET_TYPE socket, int timeout_millis, + const char * fmt, ...){ + va_list ap; + va_start(ap, fmt); + int ret = vprint_socket(socket, timeout_millis, fmt, ap); + va_end(ap); + + return ret; +} + +extern "C" +int +println_socket(NDB_SOCKET_TYPE socket, int timeout_millis, + const char * fmt, ...){ + va_list ap; + va_start(ap, fmt); + int ret = vprintln_socket(socket, timeout_millis, fmt, ap); + va_end(ap); + return ret; +} + +extern "C" +int +vprint_socket(NDB_SOCKET_TYPE socket, int timeout_millis, + const char * fmt, va_list ap){ + char buf[1000]; + char *buf2 = buf; + size_t size; + + if (fmt != 0 && fmt[0] != 0) { + size = BaseString::vsnprintf(buf, sizeof(buf), fmt, ap); + /* Check if the output was truncated */ + if(size > sizeof(buf)) { + buf2 = (char *)malloc(size); + if(buf2 == NULL) + return -1; + BaseString::vsnprintf(buf2, size, fmt, ap); + } + } else + return 0; + + int ret = write_socket(socket, timeout_millis, buf2, size); + if(buf2 != buf) + free(buf2); + return ret; +} + +extern "C" +int +vprintln_socket(NDB_SOCKET_TYPE socket, int timeout_millis, + const char * fmt, va_list ap){ + char buf[1000]; + char *buf2 = buf; + size_t size; + + if (fmt != 0 && fmt[0] != 0) { + size = BaseString::vsnprintf(buf, sizeof(buf), fmt, ap)+1;// extra byte for '/n' + /* Check if the output was truncated */ + if(size > sizeof(buf)) { + buf2 = (char *)malloc(size); + if(buf2 == NULL) + return -1; + BaseString::vsnprintf(buf2, size, fmt, ap); + } + } else { + size = 1; + } + buf2[size-1]='\n'; + + int ret = write_socket(socket, timeout_millis, buf2, size); + if(buf2 != buf) + free(buf2); + return ret; +} + +#ifdef NDB_WIN32 + +class INIT_WINSOCK2 +{ +public: + INIT_WINSOCK2(void); + ~INIT_WINSOCK2(void); + +private: + bool m_bAcceptable; +}; + +INIT_WINSOCK2 g_init_winsock2; + +INIT_WINSOCK2::INIT_WINSOCK2(void) +: m_bAcceptable(false) +{ + WORD wVersionRequested; + WSADATA wsaData; + int err; + + wVersionRequested = MAKEWORD( 2, 2 ); + + err = WSAStartup( wVersionRequested, &wsaData ); + if ( err != 0 ) { + /* Tell the user that we could not find a usable */ + /* WinSock DLL. */ + m_bAcceptable = false; + } + + /* Confirm that the WinSock DLL supports 2.2.*/ + /* Note that if the DLL supports versions greater */ + /* than 2.2 in addition to 2.2, it will still return */ + /* 2.2 in wVersion since that is the version we */ + /* requested. */ + + if ( LOBYTE( wsaData.wVersion ) != 2 || + HIBYTE( wsaData.wVersion ) != 2 ) { + /* Tell the user that we could not find a usable */ + /* WinSock DLL. */ + WSACleanup( ); + m_bAcceptable = false; + } + + /* The WinSock DLL is acceptable. Proceed. */ + m_bAcceptable = true; +} + +INIT_WINSOCK2::~INIT_WINSOCK2(void) +{ + if(m_bAcceptable) + { + m_bAcceptable = false; + WSACleanup(); + } +} + +#endif + diff --git a/storage/ndb/src/common/util/strdup.c b/storage/ndb/src/common/util/strdup.c new file mode 100644 index 00000000000..d8f4d99bd28 --- /dev/null +++ b/storage/ndb/src/common/util/strdup.c @@ -0,0 +1,28 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +#include <ndb_global.h> + +#ifndef HAVE_STRDUP +char * +strdup(const char *s){ + void *p2; + if ((p2 = malloc(strlen(s)+1))) + strcpy(p2, s); + return p2; +} +#endif diff --git a/storage/ndb/src/common/util/testConfigValues/Makefile b/storage/ndb/src/common/util/testConfigValues/Makefile new file mode 100644 index 00000000000..5b7400f5ee3 --- /dev/null +++ b/storage/ndb/src/common/util/testConfigValues/Makefile @@ -0,0 +1,12 @@ +include .defs.mk + +TYPE := util + +BIN_TARGET := testConfigValues +BIN_TARGET_ARCHIVES := portlib general + +SOURCES := testConfigValues.cpp + +CCFLAGS_LOC += -I$(call fixpath,$(NDB_TOP)/include/util) + +include $(NDB_TOP)/Epilogue.mk diff --git a/storage/ndb/src/common/util/testConfigValues/testConfigValues.cpp b/storage/ndb/src/common/util/testConfigValues/testConfigValues.cpp new file mode 100644 index 00000000000..362deb1ddad --- /dev/null +++ b/storage/ndb/src/common/util/testConfigValues/testConfigValues.cpp @@ -0,0 +1,122 @@ +#include <ConfigValues.hpp> +#include <NdbOut.hpp> +#include <stdlib.h> +#include <string.h> + +#define CF_NODES 1 +#define CF_LOG_PAGES 2 +#define CF_MEM_PAGES 3 +#define CF_START_TO 4 +#define CF_STOP_TO 5 + +void print(Uint32 i, ConfigValues::ConstIterator & cf){ + ndbout_c("---"); + for(Uint32 j = 2; j<=7; j++){ + switch(cf.getTypeOf(j)){ + case ConfigValues::IntType: + ndbout_c("Node %d : CFG(%d) : %d", + i, j, cf.get(j, 999)); + break; + case ConfigValues::Int64Type: + ndbout_c("Node %d : CFG(%d) : %lld (64)", + i, j, cf.get64(j, 999)); + break; + case ConfigValues::StringType: + ndbout_c("Node %d : CFG(%d) : %s", + i, j, cf.get(j, "<NOT FOUND>")); + break; + default: + ndbout_c("Node %d : CFG(%d) : TYPE: %d", + i, j, cf.getTypeOf(j)); + } + } +} + +void print(Uint32 i, ConfigValues & _cf){ + ConfigValues::ConstIterator cf(_cf); + print(i, cf); +} + +void +print(ConfigValues & _cf){ + ConfigValues::ConstIterator cf(_cf); + Uint32 i = 0; + while(cf.openSection(CF_NODES, i)){ + print(i, cf); + cf.closeSection(); + i++; + } +} + +inline +void +require(bool b){ + if(!b) + abort(); +} + +int +main(void){ + + { + ConfigValuesFactory cvf(10, 20); + cvf.openSection(1, 0); + cvf.put(2, 12); + cvf.put64(3, 13); + cvf.put(4, 14); + cvf.put64(5, 15); + cvf.put(6, "Keso"); + cvf.put(7, "Kent"); + cvf.closeSection(); + + cvf.openSection(1, 1); + cvf.put(2, 22); + cvf.put64(3, 23); + cvf.put(4, 24); + cvf.put64(5, 25); + cvf.put(6, "Kalle"); + cvf.put(7, "Anka"); + cvf.closeSection(); + + ndbout_c("-- print --"); + print(* cvf.m_cfg); + + cvf.shrink(); + ndbout_c("shrink\n-- print --"); + print(* cvf.m_cfg); + cvf.expand(10, 10); + ndbout_c("expand\n-- print --"); + print(* cvf.m_cfg); + + ndbout_c("packed size: %d", cvf.m_cfg->getPackedSize()); + + ConfigValues::ConstIterator iter(* cvf.m_cfg); + iter.openSection(CF_NODES, 0); + ConfigValues * cfg2 = ConfigValuesFactory::extractCurrentSection(iter); + print(99, * cfg2); + + cvf.shrink(); + ndbout_c("packed size: %d", cfg2->getPackedSize()); + + UtilBuffer buf; + Uint32 l1 = cvf.m_cfg->pack(buf); + Uint32 l2 = cvf.m_cfg->getPackedSize(); + require(l1 == l2); + + ConfigValuesFactory cvf2; + require(cvf2.unpack(buf)); + UtilBuffer buf2; + cvf2.shrink(); + Uint32 l3 = cvf2.m_cfg->pack(buf2); + require(l1 == l3); + + ndbout_c("unpack\n-- print --"); + print(* cvf2.m_cfg); + + cfg2->~ConfigValues();; + cvf.m_cfg->~ConfigValues(); + free(cfg2); + free(cvf.m_cfg); + } + return 0; +} diff --git a/storage/ndb/src/common/util/testProperties/Makefile b/storage/ndb/src/common/util/testProperties/Makefile new file mode 100644 index 00000000000..343c07a49e7 --- /dev/null +++ b/storage/ndb/src/common/util/testProperties/Makefile @@ -0,0 +1,9 @@ +include .defs.mk + +TYPE := util + +BIN_TARGET := keso + +SOURCES := testProperties.cpp + +include $(NDB_TOP)/Epilogue.mk diff --git a/storage/ndb/src/common/util/testProperties/testProperties.cpp b/storage/ndb/src/common/util/testProperties/testProperties.cpp new file mode 100644 index 00000000000..e445f7ca3e4 --- /dev/null +++ b/storage/ndb/src/common/util/testProperties/testProperties.cpp @@ -0,0 +1,195 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <ndb_global.h> +#include "Properties.hpp" +#include <NdbOut.hpp> + +#include "uucode.h" + +bool +writeToFile(const Properties & p, const char * fname, bool uu = true){ + Uint32 sz = p.getPackedSize(); + char * buffer = (char*)malloc(sz); + + FILE * f = fopen(fname, "wb"); + bool res = p.pack((Uint32*)buffer); + if(res != true){ + ndbout << "Error packing" << endl; + ndbout << "p.getPropertiesErrno() = " << p.getPropertiesErrno() << endl; + ndbout << "p.getOSErrno() = " << p.getOSErrno() << endl; + } + if(uu) + uuencode(buffer, sz, f); + else { + fwrite(buffer, 1, sz, f); + } + + fclose(f); + free(buffer); + return res; +} + +bool +readFromFile(Properties & p, const char *fname, bool uu = true){ + Uint32 sz = 30000; + char * buffer = (char*)malloc(sz); + FILE * f = fopen(fname, "rb"); + if(uu) + uudecode(f, buffer, sz); + else + fread(buffer, 1, sz, f); + fclose(f); + bool res = p.unpack((Uint32*)buffer, sz); + if(res != true){ + ndbout << "Error unpacking" << endl; + ndbout << "p.getPropertiesErrno() = " << p.getPropertiesErrno() << endl; + ndbout << "p.getOSErrno() = " << p.getOSErrno() << endl; + } + free(buffer); + return res; +} + +void putALot(Properties & tmp){ + int i = 123; + tmp.put("LockPagesInMainMemory", i++); + tmp.put("SleepWhenIdle", i++); + tmp.put("NoOfSignalsToExecuteBetweenCommunicationInterfacePoll", i++); + tmp.put("TimeBetweenWatchDogCheck", i++); + tmp.put("StopOnError", i++); + + tmp.put("MaxNoOfConcurrentOperations", i++); + tmp.put("MaxNoOfConcurrentTransactions", i++); + tmp.put("MemorySpaceIndexes", i++); + tmp.put("MemorySpaceTuples", i++); + tmp.put("MemoryDiskPages", i++); + tmp.put("NoOfFreeDiskClusters", i++); + tmp.put("NoOfDiskClusters", i++); + + tmp.put("TimeToWaitAlive", i++); + tmp.put("HeartbeatIntervalDbDb", i++); + tmp.put("HeartbeatIntervalDbApi", i++); + tmp.put("TimeBetweenInactiveTransactionAbortCheck", i++); + + tmp.put("TimeBetweenLocalCheckpoints", i++); + tmp.put("TimeBetweenGlobalCheckpoints", i++); + tmp.put("NoOfFragmentLogFiles", i++); + tmp.put("NoOfConcurrentCheckpointsDuringRestart", i++); + tmp.put("TransactionInactiveTimeBeforeAbort", i++); + tmp.put("NoOfConcurrentProcessesHandleTakeover", i++); + + tmp.put("NoOfConcurrentCheckpointsAfterRestart", i++); + + tmp.put("NoOfDiskPagesToDiskDuringRestartTUP", i++); + tmp.put("NoOfDiskPagesToDiskAfterRestartTUP", i++); + tmp.put("NoOfDiskPagesToDiskDuringRestartACC", i++); + tmp.put("NoOfDiskPagesToDiskAfterRestartACC", i++); + + tmp.put("NoOfDiskClustersPerDiskFile", i++); + tmp.put("NoOfDiskFiles", i++); + + // Always found + tmp.put("NoOfReplicas", 33); + tmp.put("MaxNoOfAttributes", 34); + tmp.put("MaxNoOfTables", 35); +} + +int +main(void){ + Properties p; + + p.put("Kalle", 1); + p.put("Ank1", "anka"); + p.put("Ank2", "anka"); + p.put("Ank3", "anka"); + p.put("Ank4", "anka"); + putALot(p); + + Properties tmp; + tmp.put("Type", "TCP"); + tmp.put("OwnNodeId", 1); + tmp.put("RemoteNodeId", 2); + tmp.put("OwnHostName", "local"); + tmp.put("RemoteHostName", "remote"); + + tmp.put("SendSignalId", 1); + tmp.put("Compression", (Uint32)false); + tmp.put("Checksum", 1); + + tmp.put64("SendBufferSize", 2000); + tmp.put64("MaxReceiveSize", 1000); + + tmp.put("PortNumber", 1233); + putALot(tmp); + + p.put("Connection", 1, &tmp); + + p.put("NoOfConnections", 2); + p.put("NoOfConnection2", 2); + + p.put("kalle", 3); + p.put("anka", "kalle"); + + Properties p2; + p2.put("kalle", "anka"); + + p.put("prop", &p2); + + p.put("Connection", 2, &tmp); + + p.put("Connection", 3, &tmp); + + p.put("Connection", 4, &tmp); + /* + */ + + Uint32 a = 99; + const char * b; + const Properties * p3; + Properties * p4; + + bool bb = p.get("kalle", &a); + bool cc = p.get("anka", &b); + bool dd = p.get("prop", &p3); + if(p.getCopy("prop", &p4)) + delete p4; + + p2.put("p2", &p2); + + p.put("prop2", &p2); + /* */ + + p.print(stdout, "testing 1: "); + + writeToFile(p, "A_1"); + writeToFile(p, "B_1", false); + + Properties r1; + readFromFile(r1, "A_1"); + writeToFile(r1, "A_3"); + + //r1.print(stdout, "testing 2: "); + Properties r2; + readFromFile(r2, "A_1"); + writeToFile(r2, "A_4"); + + Properties r3; + readFromFile(r3, "B_1", false); + writeToFile(r3, "A_5"); + r3.print(stdout, "testing 3: "); + + return 0; +} diff --git a/storage/ndb/src/common/util/testSimpleProperties/Makefile b/storage/ndb/src/common/util/testSimpleProperties/Makefile new file mode 100644 index 00000000000..89d33fa8dd8 --- /dev/null +++ b/storage/ndb/src/common/util/testSimpleProperties/Makefile @@ -0,0 +1,12 @@ +include .defs.mk + +TYPE := util + +BIN_TARGET := sp_test +BIN_TARGET_ARCHIVES := portlib general + +SOURCES := sp_test.cpp + +CCFLAGS_LOC += -I$(call fixpath,$(NDB_TOP)/include/util) + +include $(NDB_TOP)/Epilogue.mk diff --git a/storage/ndb/src/common/util/testSimpleProperties/sp_test.cpp b/storage/ndb/src/common/util/testSimpleProperties/sp_test.cpp new file mode 100644 index 00000000000..d4052b64132 --- /dev/null +++ b/storage/ndb/src/common/util/testSimpleProperties/sp_test.cpp @@ -0,0 +1,95 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <ndb_global.h> + +#include "SimpleProperties.hpp" +#include <NdbOut.hpp> + +Uint32 page[8192]; + +int writer(); +int reader(Uint32 *, Uint32 len); +int unpack(Uint32 *, Uint32 len); + +int main(){ + int len = writer(); + reader(page, len); + unpack(page, len); + + return 0; +} + +int +writer(){ + LinearWriter w(&page[0], 8192); + + w.first(); + w.add(1, 2); + w.add(7, 3); + w.add(3, "jonas"); + w.add(5, "0123456789"); + w.add(7, 4); + w.add(3, "e cool"); + w.add(5, "9876543210"); + + ndbout_c("WordsUsed = %d", w.getWordsUsed()); + + return w.getWordsUsed(); +} + +int +reader(Uint32 * pages, Uint32 len){ + SimplePropertiesLinearReader it(pages, len); + + it.printAll(ndbout); + return 0; +} + +struct Test { + Uint32 val1; + Uint32 val7; + char val3[100]; + Test() : val1(0xFFFFFFFF), val7(0xFFFFFFFF) { sprintf(val3, "bad");} +}; + +static const +SimpleProperties::SP2StructMapping +test_map [] = { + { 1, offsetof(Test, val1), SimpleProperties::Uint32Value, 0, ~0 }, + { 7, offsetof(Test, val7), SimpleProperties::Uint32Value, 0, ~0 }, + { 3, offsetof(Test, val3), SimpleProperties::StringValue, 0, sizeof(100) }, + { 5, 0, SimpleProperties::InvalidValue, 0, 0 } +}; + +static unsigned +test_map_sz = sizeof(test_map)/sizeof(test_map[0]); + +int +unpack(Uint32 * pages, Uint32 len){ + Test test; + SimplePropertiesLinearReader it(pages, len); + SimpleProperties::UnpackStatus status; + while((status = SimpleProperties::unpack(it, &test, test_map, test_map_sz, + true, false)) == SimpleProperties::Break){ + ndbout << "test.val1 = " << test.val1 << endl; + ndbout << "test.val7 = " << test.val7 << endl; + ndbout << "test.val3 = " << test.val3 << endl; + it.next(); + } + assert(status == SimpleProperties::Eof); + return 0; +} diff --git a/storage/ndb/src/common/util/uucode.c b/storage/ndb/src/common/util/uucode.c new file mode 100644 index 00000000000..da34d565153 --- /dev/null +++ b/storage/ndb/src/common/util/uucode.c @@ -0,0 +1,234 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +#include <ndb_global.h> + +/* ENC is the basic 1 character encoding function to make a char printing */ +/* DEC is single character decode */ +#define ENC(c) ((c) ? ((c) & 077) + ' ': '`') +#define DEC(c) (((c) - ' ') & 077) + +/* + * copy from in to out, encoding as you go along. + */ +void +uuencode(const char * data, int dataLen, FILE * out) +{ + int ch, n; + const char *p = data; + + fprintf(out, "begin\n"); + + while (dataLen > 0){ + n = dataLen > 45 ? 45 : dataLen; + dataLen -= n; + ch = ENC(n); + if (putc(ch, out) == EOF) + break; + for (; n > 0; n -= 3, p += 3) { + char p_0 = * p; + char p_1 = 0; + char p_2 = 0; + + if(n >= 2){ + p_1 = p[1]; + } + if(n >= 3){ + p_2 = p[2]; + } + + ch = p_0 >> 2; + ch = ENC(ch); + if (putc(ch, out) == EOF) + break; + ch = ((p_0 << 4) & 060) | ((p_1 >> 4) & 017); + ch = ENC(ch); + if (putc(ch, out) == EOF) + break; + ch = ((p_1 << 2) & 074) | ((p_2 >> 6) & 03); + ch = ENC(ch); + if (putc(ch, out) == EOF) + break; + ch = p_2 & 077; + ch = ENC(ch); + if (putc(ch, out) == EOF) + break; + } + if (putc('\n', out) == EOF) + break; + } + ch = ENC('\0'); + putc(ch, out); + putc('\n', out); + fprintf(out, "end\n"); +} + +int +uudecode(FILE * input, char * outBuf, int bufLen){ + int n; + char ch, *p, returnCode; + char buf[255]; + + returnCode = 0; + /* search for header line */ + do { + if (!fgets(buf, sizeof(buf), input)) { + return 1; + } + } while (strncmp(buf, "begin", 5)); + + /* for each input line */ + for (;;) { + if (!fgets(p = buf, sizeof(buf), input)) { + return 1; + } + /* + * `n' is used to avoid writing out all the characters + * at the end of the file. + */ + if ((n = DEC(*p)) <= 0) + break; + if(n >= bufLen){ + returnCode = 1; + break; + } + for (++p; n > 0; p += 4, n -= 3) + if (n >= 3) { + ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4; + * outBuf = ch; outBuf++; bufLen--; + ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2; + * outBuf = ch; outBuf++; bufLen--; + ch = DEC(p[2]) << 6 | DEC(p[3]); + * outBuf = ch; outBuf++; bufLen--; + } else { + if (n >= 1) { + ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4; + * outBuf = ch; outBuf++; bufLen--; + } + if (n >= 2) { + ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2; + * outBuf = ch; outBuf++; bufLen--; + } + if (n >= 3) { + ch = DEC(p[2]) << 6 | DEC(p[3]); + * outBuf = ch; outBuf++; bufLen--; + } + } + } + if (!fgets(buf, sizeof(buf), input) || strcmp(buf, "end\n")) { + return 1; + } + return returnCode; +} + +int +uuencode_mem(char * dst, const char * data, int dataLen) +{ + int sz = 0; + + int ch, n; + const char *p = data; + + while (dataLen > 0){ + n = dataLen > 45 ? 45 : dataLen; + dataLen -= n; + ch = ENC(n); + * dst = ch; dst++; sz++; + for (; n > 0; n -= 3, p += 3) { + char p_0 = * p; + char p_1 = 0; + char p_2 = 0; + + if(n >= 2){ + p_1 = p[1]; + } + if(n >= 3){ + p_2 = p[2]; + } + + ch = p_0 >> 2; + ch = ENC(ch); + * dst = ch; dst++; sz++; + + ch = ((p_0 << 4) & 060) | ((p_1 >> 4) & 017); + ch = ENC(ch); + * dst = ch; dst++; sz++; + + ch = ((p_1 << 2) & 074) | ((p_2 >> 6) & 03); + ch = ENC(ch); + * dst = ch; dst++; sz++; + + ch = p_2 & 077; + ch = ENC(ch); + * dst = ch; dst++; sz++; + } + + * dst = '\n'; dst++; sz++; + } + ch = ENC('\0'); + * dst = ch; dst++; sz++; + + * dst = '\n'; dst++; sz++; + * dst = 0; dst++; sz++; + + return sz; +} + +int +uudecode_mem(char * outBuf, int bufLen, const char * src){ + int n; + char ch; + int sz = 0; + const char * p = src; + + /* + * `n' is used to avoid writing out all the characters + * at the end of the file. + */ + if ((n = DEC(*p)) <= 0) + return 0; + if(n >= bufLen){ + return -1; + } + for (++p; n > 0; p += 4, n -= 3){ + if (n >= 3) { + ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4; + * outBuf = ch; outBuf++; bufLen--; sz++; + ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2; + * outBuf = ch; outBuf++; bufLen--; sz++; + ch = DEC(p[2]) << 6 | DEC(p[3]); + * outBuf = ch; outBuf++; bufLen--; sz++; + } else { + if (n >= 1) { + ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4; + * outBuf = ch; outBuf++; bufLen--; sz++; + } + if (n >= 2) { + ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2; + * outBuf = ch; outBuf++; bufLen--; sz++; + } + if (n >= 3) { + ch = DEC(p[2]) << 6 | DEC(p[3]); + * outBuf = ch; outBuf++; bufLen--; sz++; + } + } + } + return sz; +} + + + diff --git a/storage/ndb/src/common/util/version.c b/storage/ndb/src/common/util/version.c new file mode 100644 index 00000000000..dfbb1e4a2e6 --- /dev/null +++ b/storage/ndb/src/common/util/version.c @@ -0,0 +1,238 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <ndb_global.h> +#include <ndb_version.h> +#include <version.h> +#include <basestring_vsnprintf.h> +#include <NdbEnv.h> +#include <NdbOut.hpp> + +Uint32 getMajor(Uint32 version) { + return (version >> 16) & 0xFF; +} + +Uint32 getMinor(Uint32 version) { + return (version >> 8) & 0xFF; +} + +Uint32 getBuild(Uint32 version) { + return (version >> 0) & 0xFF; +} + +Uint32 makeVersion(Uint32 major, Uint32 minor, Uint32 build) { + return MAKE_VERSION(major, minor, build); + +} + +const char * getVersionString(Uint32 version, const char * status) { + char buff[100]; + if (status && status[0] != 0) + basestring_snprintf(buff, sizeof(buff), + "Version %d.%d.%d (%s)", + getMajor(version), + getMinor(version), + getBuild(version), + status); + else + basestring_snprintf(buff, sizeof(buff), + "Version %d.%d.%d", + getMajor(version), + getMinor(version), + getBuild(version)); + return strdup(buff); +} + +typedef enum { + UG_Null, + UG_Range, + UG_Exact +} UG_MatchType; + +struct NdbUpGradeCompatible { + Uint32 ownVersion; + Uint32 otherVersion; + UG_MatchType matchType; +}; + +/*#define TEST_VERSION*/ + +#define HAVE_NDB_SETVERSION +#ifdef HAVE_NDB_SETVERSION +Uint32 ndbOwnVersionTesting = 0; +void +ndbSetOwnVersion() { + char buf[256]; + if (NdbEnv_GetEnv("NDB_SETVERSION", buf, sizeof(buf))) { + Uint32 _v1,_v2,_v3; + if (sscanf(buf, "%u.%u.%u", &_v1, &_v2, &_v3) == 3) { + ndbOwnVersionTesting = MAKE_VERSION(_v1,_v2,_v3); + ndbout_c("Testing: Version set to 0x%x", ndbOwnVersionTesting); + } + } +} +#else +void ndbSetOwnVersion() {} +#endif + +#ifndef TEST_VERSION +struct NdbUpGradeCompatible ndbCompatibleTable_full[] = { + { MAKE_VERSION(5,0,3), MAKE_VERSION(5,0,2), UG_Exact }, + { MAKE_VERSION(4,1,9), MAKE_VERSION(4,1,8), UG_Exact }, + { MAKE_VERSION(3,5,2), MAKE_VERSION(3,5,1), UG_Exact }, + { 0, 0, UG_Null } +}; + +struct NdbUpGradeCompatible ndbCompatibleTable_upgrade[] = { + { MAKE_VERSION(5,0,2), MAKE_VERSION(4,1,8), UG_Exact }, + { MAKE_VERSION(3,5,4), MAKE_VERSION(3,5,3), UG_Exact }, + { 0, 0, UG_Null } +}; + +#else /* testing purposes */ + +struct NdbUpGradeCompatible ndbCompatibleTable_full[] = { + { MAKE_VERSION(4,1,5), MAKE_VERSION(4,1,0), UG_Range }, + { MAKE_VERSION(3,6,9), MAKE_VERSION(3,6,1), UG_Range }, + { MAKE_VERSION(3,6,2), MAKE_VERSION(3,6,1), UG_Range }, + { MAKE_VERSION(3,5,7), MAKE_VERSION(3,5,0), UG_Range }, + { MAKE_VERSION(3,5,1), MAKE_VERSION(3,5,0), UG_Range }, + { NDB_VERSION_D , MAKE_VERSION(NDB_VERSION_MAJOR,NDB_VERSION_MINOR,2), UG_Range }, + { 0, 0, UG_Null } +}; + +struct NdbUpGradeCompatible ndbCompatibleTable_upgrade[] = { + { MAKE_VERSION(4,1,5), MAKE_VERSION(3,6,9), UG_Exact }, + { MAKE_VERSION(3,6,2), MAKE_VERSION(3,5,7), UG_Exact }, + { MAKE_VERSION(3,5,1), NDB_VERSION_D , UG_Exact }, + { 0, 0, UG_Null } +}; + + +#endif + +void ndbPrintVersion() +{ + printf("Version: %u.%u.%u\n", + getMajor(ndbGetOwnVersion()), + getMinor(ndbGetOwnVersion()), + getBuild(ndbGetOwnVersion())); +} + +Uint32 +ndbGetOwnVersion() +{ +#ifdef HAVE_NDB_SETVERSION + if (ndbOwnVersionTesting == 0) + return NDB_VERSION_D; + else + return ndbOwnVersionTesting; +#else + return NDB_VERSION_D; +#endif +} + +int +ndbSearchUpgradeCompatibleTable(Uint32 ownVersion, Uint32 otherVersion, + struct NdbUpGradeCompatible table[]) +{ + int i; + for (i = 0; table[i].ownVersion != 0 && table[i].otherVersion != 0; i++) { + if (table[i].ownVersion == ownVersion || + table[i].ownVersion == (Uint32) ~0) { + switch (table[i].matchType) { + case UG_Range: + if (otherVersion >= table[i].otherVersion){ + return 1; + } + break; + case UG_Exact: + if (otherVersion == table[i].otherVersion){ + return 1; + } + break; + default: + break; + } + } + } + return 0; +} + +int +ndbCompatible(Uint32 ownVersion, Uint32 otherVersion, struct NdbUpGradeCompatible table[]) +{ + if (otherVersion >= ownVersion) { + return 1; + } + return ndbSearchUpgradeCompatibleTable(ownVersion, otherVersion, table); +} + +int +ndbCompatible_full(Uint32 ownVersion, Uint32 otherVersion) +{ + return ndbCompatible(ownVersion, otherVersion, ndbCompatibleTable_full); +} + +int +ndbCompatible_upgrade(Uint32 ownVersion, Uint32 otherVersion) +{ + if (ndbCompatible_full(ownVersion, otherVersion)) + return 1; + return ndbCompatible(ownVersion, otherVersion, ndbCompatibleTable_upgrade); +} + +int +ndbCompatible_mgmt_ndb(Uint32 ownVersion, Uint32 otherVersion) +{ + return ndbCompatible_upgrade(ownVersion, otherVersion); +} + +int +ndbCompatible_mgmt_api(Uint32 ownVersion, Uint32 otherVersion) +{ + return ndbCompatible_upgrade(ownVersion, otherVersion); +} + +int +ndbCompatible_ndb_mgmt(Uint32 ownVersion, Uint32 otherVersion) +{ + return ndbCompatible_full(ownVersion, otherVersion); +} + +int +ndbCompatible_api_mgmt(Uint32 ownVersion, Uint32 otherVersion) +{ + return ndbCompatible_full(ownVersion, otherVersion); +} + +int +ndbCompatible_api_ndb(Uint32 ownVersion, Uint32 otherVersion) +{ + return ndbCompatible_full(ownVersion, otherVersion); +} + +int +ndbCompatible_ndb_api(Uint32 ownVersion, Uint32 otherVersion) +{ + return ndbCompatible_upgrade(ownVersion, otherVersion); +} + +int +ndbCompatible_ndb_ndb(Uint32 ownVersion, Uint32 otherVersion) +{ + return ndbCompatible_upgrade(ownVersion, otherVersion); +} |