Example #1
0
File: persist.cpp Project: aosm/tcl
void c4_Differ::CreateDiff(int id_, c4_Column &col_) {
  _temp.SetSize(0);
#if 0
  t4_i32 offset = 0;
  t4_i32 savedOff = 0;
  t4_i32 savedLen = 0;

  c4_Strategy *strat = col_.Persist() != 0 ? &col_.Strategy(): 0;

  c4_ColIter iter(col_, 0, col_.ColSize());
  while (iter.Next()) {
    const t4_byte *p = iter.BufLoad();
    if (strat != 0 && strat->_mapStart != 0 && p >= strat->_mapStart && p -
      strat->_mapStart < strat->_dataSize) {
      t4_i32 nextOff = p - strat->_mapStart;
      if (savedLen == 0)
        savedOff = nextOff;
      if (nextOff == savedOff + savedLen) {
        savedLen += iter.BufLen();
        continue;
      }

      if (savedLen > 0)
        AddEntry(savedOff, savedLen, c4_Bytes());

      savedOff = nextOff;
      savedLen = iter.BufLen();
    } else {
      AddEntry(savedOff, savedLen, c4_Bytes(p, iter.BufLen()));
      savedLen = 0;
    }

    offset += iter.BufLen();
  }

  c4_View diff = pDiff(_diffs[id_]);
  if (_temp.GetSize() != diff.GetSize() || _temp != diff)
#else 
    c4_Bytes t1;
  const t4_byte *p = col_.FetchBytes(0, col_.ColSize(), t1, false);
  AddEntry(0, 0, c4_Bytes(p, col_.ColSize()));
#endif 
  pDiff(_diffs[id_]) = _temp;

  pOrig(_diffs[id_]) = col_.Position();
}
Example #2
0
void c4_Handler::ClearBytes(c4_Bytes &buf_)const
{
    static char zeros[8];

    int n = f4_ClearFormat(Property().Type());
    d4_assert(n <= sizeof zeros);

    buf_ = c4_Bytes(zeros, n);
}
Example #3
0
File: persist.cpp Project: aosm/tcl
void c4_SaveContext::FlushBuffer() {
  int n = _curr - _bufPtr;
  if (_walk != 0 && n > 0) {
    t4_i32 end = _walk->ColSize();
    _walk->Grow(end, n);
    _walk->StoreBytes(end, c4_Bytes(_bufPtr, n));
  }

  _curr = _bufPtr = _buffer;
  _limit = _buffer + sizeof _buffer;
}
void c4_FormatS::Set(int index_, const c4_Bytes &buf_) {
  int m = buf_.Size();
  if (--m >= 0) {
    d4_assert(buf_.Contents()[m] == 0);
    if (m == 0) {
      SetOne(index_, c4_Bytes()); // don't store data for empty strings
      return ;
    }
  }

  SetOne(index_, buf_);
}
Example #5
0
bool c4_GroupByViewer::GetItem(int row_, int col_, c4_Bytes& buf_)
{
  if (col_ < _keys.NumProperties())
    return _sorted.GetItem(_map.GetAt(row_), col_, buf_);

  d4_assert(col_ == _keys.NumProperties());
  
  t4_i32 count;
  switch (_result.Type())
  {
    case 'I': count = _map.GetAt(row_ + 1) - _map.GetAt(row_);
          buf_ = c4_Bytes (&count, sizeof count, true);
          break;
    case 'V': _temp = _sorted.Slice(_map.GetAt(row_), _map.GetAt(row_ + 1))
                .ProjectWithout(_keys);
          buf_ = c4_Bytes (&_temp, sizeof _temp, true);
          break;
    default:  d4_assert(0);
  }

  return true;
}
void c4_FormatS::Insert(int index_, const c4_Bytes &buf_, int count_) {
  d4_assert(count_ > 0);

  int m = buf_.Size();
  if (--m >= 0) {
    d4_assert(buf_.Contents()[m] == 0);
    if (m == 0) {
      c4_FormatB::Insert(index_, c4_Bytes(), count_);
      return ;
    }
  }

  c4_FormatB::Insert(index_, buf_, count_);
}
void c4_FormatB::OldDefine(char type_, c4_Persist &pers_) {
  int rows = Owner().NumRows();

  c4_ColOfInts sizes(_data.Persist());

  if (type_ == 'M') {
    InitOffsets(sizes);

    c4_ColOfInts szVec(_data.Persist());
    pers_.FetchOldLocation(szVec);
    szVec.SetRowCount(rows);

    c4_ColOfInts posVec(_data.Persist());
    pers_.FetchOldLocation(posVec);
    posVec.SetRowCount(rows);

    for (int r = 0; r < rows; ++r) {
      t4_i32 sz = szVec.GetInt(r);
      if (sz > 0) {
        c4_Column *mc = d4_new c4_Column(_data.Persist());
        d4_assert(mc != 0);
        _memos.SetAt(r, mc);

        mc->SetLocation(posVec.GetInt(r), sz);
      }
    }
  } else {
    pers_.FetchOldLocation(_data);

    if (type_ == 'B') {
      pers_.FetchOldLocation(sizes);

#if !q4_OLD_IS_ALWAYS_V2

      // WARNING - HUGE HACK AHEAD - THIS IS NOT 100% FULLPROOF!
      //
      // The above is correct for MK versions 2.0 and up, but *NOT*
      // for MK 1.8.6 datafiles, which store sizes first (OUCH!!!).
      // This means that there is not a 100% safe way to auto-convert
      // both 1.8.6 and 2.0 files - since there is no way to detect
      // unambiguously which version a datafile is.  All we can do,
      // is to carefully check both vectors, and *hope* that only one
      // of them is valid as sizes vector.  This problem applies to
      // the 'B' (bytes) property type only, and only pre 2.0 files.
      //
      // To build a version which *always* converts assuming 1.8.6,
      // add flag "-Dq4_OLD_IS_PRE_V2" to the compiler command line.
      // Conversely, "-Dq4_OLD_IS_ALWAYS_V2" forces 2.0 conversion.

      if (rows > 0) {
        t4_i32 s1 = sizes.ColSize();
        t4_i32 s2 = _data.ColSize();

#if !q4_OLD_IS_PRE_V2
        // if the size vector is clearly impossible, swap vectors
        bool fix = c4_ColOfInts::CalcAccessWidth(rows, s1) < 0;

        // if the other vector might be valid as well, check further
        if (!fix && c4_ColOfInts::CalcAccessWidth(rows, s2) >= 0) {
          sizes.SetRowCount(rows);
          t4_i32 total = 0;
          for (int i = 0; i < rows; ++i) {
            t4_i32 w = sizes.GetInt(i);
            if (w < 0 || total > s2) {
              total =  - 1;
              break;
            }
            total += w;
          }

          // if the sizes don't add up, swap vectors
          fix = total != s2;
        }

        if (fix)
#endif 
         {
          t4_i32 p1 = sizes.Position();
          t4_i32 p2 = _data.Position();
          _data.SetLocation(p1, s1);
          sizes.SetLocation(p2, s2);
        }
      }
#endif 
      InitOffsets(sizes);
    } else {
      d4_assert(type_ == 'S');

      sizes.SetRowCount(rows);

      t4_i32 pos = 0;
      t4_i32 lastEnd = 0;
      int k = 0;

      c4_ColIter iter(_data, 0, _data.ColSize());
      while (iter.Next()) {
        const t4_byte *p = iter.BufLoad();
        for (int j = 0; j < iter.BufLen(); ++j)
        if (!p[j]) {
          sizes.SetInt(k++, pos + j + 1-lastEnd);
          lastEnd = pos + j + 1;
        }

        pos += iter.BufLen();
      }

      d4_assert(pos == _data.ColSize());

      if (lastEnd < pos) {
        // last entry had no zero byte
        _data.InsertData(pos++, 1, true);
        sizes.SetInt(k, pos - lastEnd);
      }

      InitOffsets(sizes);

      // get rid of entries with just a null byte
      for (int r = 0; r < rows; ++r)
        if (c4_FormatB::ItemSize(r) == 1)
          SetOne(r, c4_Bytes());
    }
  }
}
Example #8
0
// this is how the old "Get" was, keep it until no longer needed
void c4_Handler::GetBytes(int index_, c4_Bytes &buf_, bool copySmall_)
{
    int n;
    const void *p = Get(index_, n);
    buf_ = c4_Bytes(p, n, copySmall_ && n <= 8);
}
Example #9
0
 virtual void DataCommit(t4_i32 newSize_) {
     if (newSize_ > 0)
       _memo(_view[_row]).Modify(c4_Bytes(), newSize_);
 }
void TestResize() {
  B(r00, Simple insert, 0)W(r00a);
   {
    CResizer r1("r00a");

    int n = r1.Ins(0, 250);
    A(n == 250);

  }
  D(r00a);
  R(r00a);
  E;

  B(r01, Simple removes, 0)W(r01a);
   {
    CResizer r1("r01a");
    int n;

    n = r1.Ins(0, 500);
    A(n == 500);

    n = r1.Del(0, 50);
    A(n == 450);
    n = r1.Del(350, 100);
    A(n == 350);
    n = r1.Del(25, 150);
    A(n == 200);
    n = r1.Del(0, 200);
    A(n == 0);

    n = r1.Ins(0, 15);
    A(n == 15);

  }
  D(r01a);
  R(r01a);
  E;

  B(r02, Large inserts and removes, 0)W(r02a);
   {
    int big = sizeof(int) == sizeof(short) ? 1000 : 4000;

    CResizer r1("r02a");
    int n;

    n = r1.Ins(0, 2000);
    A(n == 2000);
    n = r1.Ins(0, 3000);
    A(n == 5000);
    n = r1.Ins(5000, 1000+big);
    A(n == 6000+big);
    n = r1.Ins(100, 10);
    A(n == 6010+big);
    n = r1.Ins(4000, 100);
    A(n == 6110+big);
    n = r1.Ins(0, 1001);
    A(n == 7111+big);

    n = r1.Del(7111, big);
    A(n == 7111);
    n = r1.Del(0, 4111);
    A(n == 3000);
    n = r1.Del(10, 10);
    A(n == 2990);
    n = r1.Del(10, 10);
    A(n == 2980);
    n = r1.Del(5, 10);
    A(n == 2970);
    n = r1.Del(0, 990);
    A(n == 1980);
    n = r1.Del(3, 1975);
    A(n == 5);

  }
  D(r02a);
  R(r02a);
  E;

  B(r03, Binary property insertions, 0)W(r03a);
   {
    c4_BytesProp p1("p1");
    c4_Storage s1("r03a", 1);
    s1.SetStructure("a[p1:B]");
    c4_View v1 = s1.View("a");

    char buf[1024];

    memset(buf, 0x11, sizeof buf);
    v1.Add(p1[c4_Bytes(buf, sizeof buf)]);

    memset(buf, 0x22, sizeof buf);
    v1.Add(p1[c4_Bytes(buf, sizeof buf / 2)]);

    s1.Commit();

    memset(buf, 0x33, sizeof buf);
    p1(v1[1]) = c4_Bytes(buf, sizeof buf); // fix c4_Column::CopyData

    memset(buf, 0x44, sizeof buf);
    v1.Add(p1[c4_Bytes(buf, sizeof buf / 3)]);

    s1.Commit();

    memset(buf, 0x55, sizeof buf);
    v1.InsertAt(1, p1[c4_Bytes(buf, sizeof buf)]);

    memset(buf, 0x66, sizeof buf);
    v1.InsertAt(1, p1[c4_Bytes(buf, sizeof buf / 4)]);

    s1.Commit();

  }
  D(r03a);
  R(r03a);
  E;

  B(r04, Scripted string property tests, 0)W(r04a);
   {
    c4_StringProp p1("p1");
    c4_Storage s1("r04a", 1);
    s1.SetStructure("a[p1:S]");

    // This code implements a tiny language to specify tests in:
    //
    //  "<X>,<Y>A"  add X partial buffers of size Y
    //  "<X>a"    add X full buffers at end
    //  "<X>,<Y>C"  change entry X to a partial buffer of size Y
    //  "<X>c"    change entry at position X to a full buffer
    //  "<X>,<Y>I"  insert partial buffer of size Y at position X
    //  "<X>i"    insert a full buffer at position X
    //  "<X>,<Y>R"  remove Y entries at position X
    //  "<X>r"    remove one entry at position X
    //
    //  ">"     commit changes
    //  "<"     rollback changes
    //
    //  " "     ignore spaces
    //  "<X>,"    for additional args
    //  "<X>="    verify number of rows is X

    const char *scripts[] =  {
      //   A  B  C  D    E    F   G    H    I J
      "5a 5a 5a 1r   5r   10r   6r     2r   > 10=", 
        "5a 5a 5a 1,200C 5,200C 10,200C 6,200C 2,200C > 15=", 
        "5a 5a 5a 1,300C 5,300C 10,300C 6,300C 2,300C > 15=", 

      //   A   B   C   D     E     F      G     H     I J
      "50a 50a 50a 10r   50r   100r   60r   20r   > 145=", 
        "50a 50a 50a 10,200C 50,200C 100,200C 60,200C 20,200C > 150=", 
        "50a 50a 50a 10,300C 50,300C 100,300C 60,300C 20,300C > 150=", 

      //   A     B   C     D   E   F  G H I J
      "50,0A 50,0A 50,0A 10c 50c 100c 60c 20c > 150=",  // asserts in 1.7b1

      //   A    B   C  D E
      "3,3A 1,10C 1,1C > 3=",  // asserts in 1.7 - June 6 build

      "", 0
    };

    for (int i = 0; scripts[i]; ++i) {
      c4_View v1 = s1.View("a");
      v1.RemoveAll();
      s1.Commit();
      A(v1.GetSize() == 0); // start with a clean slate each time

      const char *p = scripts[i];

      char fill = '@';
      int save = 0;
      c4_Row row;

      while (*p) {
        // default is a string of 255 chars (with additional null byte)
        p1(row) = c4_String(++fill, 255);

        int arg = (int)strtol(p, (char **) &p, 10); // loses const

        switch (*p++) {
          case 'A':
            p1(row) = c4_String(fill, arg);
            arg = save;
          case 'a':
            while (--arg >= 0)
              v1.Add(row);
            break;
          case 'C':
            p1(row) = c4_String(fill, arg);
            arg = save;
          case 'c':
            v1.SetAt(arg, row);
            break;
          case 'I':
            p1(row) = c4_String(fill, arg);
            arg = save;
          case 'i':
            v1.InsertAt(arg, row);
            break;
          case 'R':
            v1.RemoveAt(save, arg);
            break;
          case 'r':
            v1.RemoveAt(arg);
            break;
          case '>':
            s1.Commit();
            break;
          case '<':
            s1.Rollback();
            v1 = s1.View("a");
            break;
          case ' ':
            break;
          case ',':
            save = arg;
            break;
          case '=':
            A(v1.GetSize() == arg);
            break;
        }
      }
    }

    s1.Commit();

  }
  D(r04a);
  R(r04a);
  E;
}
Example #11
0
File: tstore3.cpp Project: aosm/tcl
void TestStores3() {
  B(s20, View outlives storage, 0)W(s20a);
   {
    c4_IntProp p1("p1");
    c4_View v1;

     {
      c4_Storage s1("s20a", 1);
      v1 = s1.GetAs("a[p1:I,p2:S]");
      v1.Add(p1[123]);
    }

    // 19990916 - semantics changed, rows kept but no properties
    //A(p1 (v1[0]) == 123);
    A(v1.GetSize() == 1);
    A(v1.NumProperties() == 0);

  }
  D(s20a);
  R(s20a);
  E;

  B(s21, Test demo scenario, 0)W(s21a);
   {
    c4_StringProp p1("p1"), p2("p2");
     {
      c4_Storage storage("s21a", 1);
      storage.SetStructure("a[p1:S,p2:S]");
      c4_View v1;
      c4_Row r1;

      p1(r1) = "One";
      p2(r1) = "Un";
      v1.Add(r1);
      A(v1.GetSize() == 1);

      p1(r1) = "Two";
      p2(r1) = "Deux";
      v1.Add(r1);
      A(v1.GetSize() == 2);

      // changed 2000-03-15: Store is gone
      //v1 = storage.Store("a", v1);
      v1 = storage.View("a") = v1;

      A(v1.GetSize() == 2);
      A(p1(v1[1]) == (c4_String)"Two");
      A(p2(v1[1]) == (c4_String)"Deux");
      A(p1(v1[0]) == (c4_String)"One");
      A(p2(v1[0]) == (c4_String)"Un");

      storage.Commit();
      A(v1.GetSize() == 2);
      A(p1(v1[1]) == (c4_String)"Two");
      A(p2(v1[1]) == (c4_String)"Deux");
      A(p1(v1[0]) == (c4_String)"One");
      A(p2(v1[0]) == (c4_String)"Un");

      c4_String s1(p1(v1[1]));
      c4_String s2(p2(v1[1]));
      A(s1 == "Two");
      A(s2 == "Deux");

      storage.Commit();

      v1.Add(p1["Three"] + p2["Trois"]);

      storage.Commit();
      A(v1.GetSize() == 3);
      A(p2(v1[2]) == (c4_String)"Trois");

      v1 = storage.GetAs("a[p1:S,p2:S,p3:I]");
      A(v1.GetSize() == 3);
      A(p2(v1[2]) == (c4_String)"Trois");

      c4_IntProp p3("p3");
      p3(v1[1]) = 123;

      storage.Commit();
      A(v1.GetSize() == 3);
      A(p2(v1[2]) == (c4_String)"Trois");

      c4_View v2 = storage.GetAs("b[p4:I]");

      c4_IntProp p4("p4");
      v2.Add(p4[234]);

      storage.Commit();
      A(v1.GetSize() == 3);
      A(p2(v1[2]) == (c4_String)"Trois");

      c4_IntProp p4a("p4");
      v1.InsertAt(2, p1["Four"] + p4a[345]);

      storage.Commit();
      A(v1.GetSize() == 4);
      A(p1(v1[0]) == (c4_String)"One");
      A(p1(v1[1]) == (c4_String)"Two");
      A(p1(v1[2]) == (c4_String)"Four");
      A(p1(v1[3]) == (c4_String)"Three");
      A(p2(v1[3]) == (c4_String)"Trois");
      A(v2.GetSize() == 1);
      A(p4(v2[0]) == 234);
    }
     {
      c4_Storage storage("s21a", 0);
      c4_View v1 = storage.View("a");
      A(v1.GetSize() == 4);
      A(p1(v1[0]) == (c4_String)"One");
      A(p1(v1[1]) == (c4_String)"Two");
      A(p1(v1[2]) == (c4_String)"Four");
      A(p1(v1[3]) == (c4_String)"Three");
      c4_View v2 = storage.View("b");
      c4_IntProp p4("p4");
      A(v2.GetSize() == 1);
      A(p4(v2[0]) == 234);
    }
  }
  D(s21a);
  R(s21a);
  E;

#if !q4_TINY
  B(s22, Double storage, 0)W(s22a);
   {
    c4_DoubleProp p1("p1");
    c4_Storage s1("s22a", 1);
    s1.SetStructure("a[p1:D]");
    c4_View v1 = s1.View("a");
    v1.Add(p1[1234.5678]);
    v1.Add(p1[2345.6789]);
    v1.InsertAt(1, p1[3456.7890]);
    s1.Commit();
  }
  D(s22a);
  R(s22a);
  E;
#endif 

  B(s23, Find absent record, 0)W(s23a);
   {
    c4_Storage s1("s23a", 1);
    s1.SetStructure("v[h:S,p:I,a:I,b:I,c:I,d:I,e:I,f:I,g:I,x:I]");
    c4_View view = s1.View("v");

    c4_StringProp H("h");
    c4_IntProp P("p");

    c4_Row row;
    H(row) = "someString";
    P(row) = 99;

    int x = view.Find(row);
    A(x ==  - 1);

  }
  D(s23a);
  R(s23a);
  E;

  B(s24, Bitwise storage, 0)W(s24a);
   {
    c4_IntProp p1("p1");

    int m = 9;

    // insert values in front, but check fractional sizes at each step
    for (int n = 0; n < m; ++n) {
       {
        c4_Storage s1("s24a", 1);
        s1.SetStructure("a1[p1:I],a2[p1:I],a3[p1:I],a4[p1:I]");
        s1.AutoCommit(); // new feature in 1.6

        c4_View v1 = s1.View("a1");
        c4_View v2 = s1.View("a2");
        c4_View v3 = s1.View("a3");
        c4_View v4 = s1.View("a4");

        c4_Row row;
        int k = ~n;

        p1(row) = k &0x01;
        v1.InsertAt(0, row);

        p1(row) = k &0x03;
        v2.InsertAt(0, row);

        p1(row) = k &0x0F;
        v3.InsertAt(0, row);

        p1(row) = k &0x7F;
        v4.InsertAt(0, row);
      }
      // the following checks that all tiny size combinations work
       {
        c4_Storage s1("s24a", 0);

        c4_View v1 = s1.View("a1");
        c4_View v2 = s1.View("a2");
        c4_View v3 = s1.View("a3");
        c4_View v4 = s1.View("a4");

        A(v1.GetSize() == n + 1);
        A(v2.GetSize() == n + 1);
        A(v3.GetSize() == n + 1);
        A(v4.GetSize() == n + 1);
      }
    }

    c4_Storage s1("s24a", 0);

    c4_View v1 = s1.View("a1");
    c4_View v2 = s1.View("a2");
    c4_View v3 = s1.View("a3");
    c4_View v4 = s1.View("a4");

    A(v1.GetSize() == m);
    A(v2.GetSize() == m);
    A(v3.GetSize() == m);
    A(v4.GetSize() == m);

    // now check that the inserted values are correct
    for (int i = 0; i < m; ++i) {
      int j = m - i - 1;
      int k = ~i;

      A(p1(v1[j]) == (k &0x01));
      A(p1(v2[j]) == (k &0x03));
      A(p1(v3[j]) == (k &0x0F));
      A(p1(v4[j]) == (k &0x7F));
    }

  }
  D(s24a);
  R(s24a);
  E;

  B(s25, Bytes storage, 0)W(s25a);
   {
    c4_Bytes hi("hi", 2);
    c4_Bytes gday("gday", 4);
    c4_Bytes hello("hello", 5);

    c4_BytesProp p1("p1");
    c4_Storage s1("s25a", 1);
    s1.SetStructure("a[p1:B]");
    c4_View v1 = s1.View("a");

    v1.Add(p1[hi]);
    A(p1(v1[0]) == hi);
    v1.Add(p1[hello]);
    A(p1(v1[0]) == hi);
    A(p1(v1[1]) == hello);
    v1.InsertAt(1, p1[gday]);
    A(p1(v1[0]) == hi);
    A(p1(v1[1]) == gday);
    A(p1(v1[2]) == hello);
    s1.Commit();
    A(p1(v1[0]) == hi);
    A(p1(v1[1]) == gday);
    A(p1(v1[2]) == hello);

  }
  D(s25a);
  R(s25a);
  E;

  B(s26, Bitwise autosizing, 0)W(s26a);
   {
    c4_IntProp p1("p1"), p2("p2"), p3("p3"), p4("p4");
    c4_Storage s1("s26a", 1);
    s1.SetStructure("a[p1:I,p2:I,p3:I,p4:I]");
    c4_View v1 = s1.View("a");

    v1.Add(p1[1] + p2[3] + p3[15] + p4[127]);
    A(p1(v1[0]) == 1);
    A(p2(v1[0]) == 3);
    A(p3(v1[0]) == 15);
    A(p4(v1[0]) == 127);

    p1(v1[0]) = 100000L;
    p2(v1[0]) = 100000L;
    p3(v1[0]) = 100000L;
    p4(v1[0]) = 100000L;

    // these failed in 1.61
    A(p1(v1[0]) == 100000L);
    A(p2(v1[0]) == 100000L);
    A(p3(v1[0]) == 100000L);
    A(p4(v1[0]) == 100000L);

    s1.Commit();

  }
  D(s26a);
  R(s26a);
  E;

  B(s27, Bytes restructuring, 0)W(s27a);
   {
    c4_Bytes test("test", 4);

    c4_BytesProp p1("p1");
    c4_Storage s1("s27a", 1);

    c4_Row row;
    p1(row) = test;

    c4_View v1;
    v1.Add(row);

    // changed 2000-03-15: Store is gone
    //s1.Store("a", v1); // asserts in 1.61
    c4_View v2 = s1.GetAs("a[p1:B]");
    v2.InsertAt(0, v1);

    s1.Commit();

  }
  D(s27a);
  R(s27a);
  E;

#if !q4_TINY
  B(s28, Doubles added later, 0)W(s28a);
   {
    c4_FloatProp p1("p1");
    c4_DoubleProp p2("p2");
    c4_ViewProp p3("p3");

    c4_Storage s1("s28a", 1);
    s1.SetStructure("a[p1:F,p2:D,p3[p1:F,p2:D]]");
    c4_View v1 = s1.View("a");

    c4_Row r1;

    p1(r1) = 123;
    p2(r1) = 123;

    c4_View v2;
    v2.Add(p1[234] + p2[234]);
    p3(r1) = v2;

    v1.Add(r1);
    double x1 = p1(v1[0]);
    A(x1 == p2(v1[0]));

    v2 = p3(v1[0]);
    double x2 = p1(v2[0]);
    A(x2 == p2(v2[0])); // fails in 1.6

    s1.Commit();

  }
  D(s28a);
  R(s28a);
  E;
#endif 

  B(s29, Delete bytes property, 0)W(s29a);
   {
     {
      c4_BytesProp p1("p1");

      c4_Storage s1("s29a", 1);
      s1.SetStructure("a[p1:B]");
      c4_View v1 = s1.View("a");

      int data = 99;
      v1.Add(p1[c4_Bytes(&data, sizeof data)]);

      s1.Commit();
    }
     {
      c4_Storage s1("s29a", 1);
      c4_View v1 = s1.View("a");

      v1.RemoveAt(0); // asserts in 1.7

      s1.Commit();
    }

  }
  D(s29a);
  R(s29a);
  E;
}
Example #12
0
File: tstore4.cpp Project: aosm/tcl
void TestStores4() {
  B(s30, Memo storage, 0)W(s30a);
   {
    c4_Bytes hi("hi", 2);
    c4_Bytes gday("gday", 4);
    c4_Bytes hello("hello", 5);

    c4_MemoProp p1("p1");
    c4_Storage s1("s30a", 1);
    s1.SetStructure("a[p1:B]");
    c4_View v1 = s1.View("a");

    v1.Add(p1[hi]);
    A(p1(v1[0]) == hi);
    v1.Add(p1[hello]);
    A(p1(v1[0]) == hi);
    A(p1(v1[1]) == hello);
    v1.InsertAt(1, p1[gday]);
    A(p1(v1[0]) == hi);
    A(p1(v1[1]) == gday);
    A(p1(v1[2]) == hello);
    s1.Commit();
    A(p1(v1[0]) == hi);
    A(p1(v1[1]) == gday);
    A(p1(v1[2]) == hello);

  }
  D(s30a);
  R(s30a);
  E;

  // this failed in the unbuffered 1.8.5a interim release in Mk4tcl 1.0.5
  B(s31, Check sort buffer use, 0)W(s31a);
   {
    c4_IntProp p1("p1");
    c4_Storage s1("s31a", 1);
    s1.SetStructure("a[p1:I]");
    c4_View v1 = s1.View("a");
    v1.Add(p1[3]);
    v1.Add(p1[1]);
    v1.Add(p1[2]);
    s1.Commit();

    c4_View v2 = v1.SortOn(p1);
    A(v2.GetSize() == 3);
    A(p1(v2[0]) == 1);
    A(p1(v2[1]) == 2);
    A(p1(v2[2]) == 3);

  }
  D(s31a);
  R(s31a);
  E;

  // this failed in 1.8.6, fixed 19990828
  B(s32, Set memo empty or same size, 0)W(s32a);
   {
    c4_Bytes empty;
    c4_Bytes full("full", 4);
    c4_Bytes more("more", 4);

    c4_MemoProp p1("p1");
    c4_Storage s1("s32a", 1);
    s1.SetStructure("a[p1:B]");
    c4_View v1 = s1.View("a");

    v1.Add(p1[full]);
    A(p1(v1[0]) == full);
    s1.Commit();
    A(p1(v1[0]) == full);

    p1(v1[0]) = empty;
    A(p1(v1[0]) == empty);
    s1.Commit();
    A(p1(v1[0]) == empty);

    p1(v1[0]) = more;
    A(p1(v1[0]) == more);
    s1.Commit();
    A(p1(v1[0]) == more);

    p1(v1[0]) = full;
    A(p1(v1[0]) == full);
    s1.Commit();
    A(p1(v1[0]) == full);

  }
  D(s32a);
  R(s32a);
  E;

  // this failed in 1.8.6, fixed 19990828
  B(s33, Serialize memo fields, 0)W(s33a);
  W(s33b);
  W(s33c);
   {
    c4_Bytes hi("hi", 2);
    c4_Bytes gday("gday", 4);
    c4_Bytes hello("hello", 5);

    c4_MemoProp p1("p1");

    c4_Storage s1("s33a", 1);
    s1.SetStructure("a[p1:B]");
    c4_View v1 = s1.View("a");

    v1.Add(p1[hi]);
    v1.Add(p1[gday]);
    v1.Add(p1[hello]);
    A(p1(v1[0]) == hi);
    A(p1(v1[1]) == gday);
    A(p1(v1[2]) == hello);
    s1.Commit();
    A(p1(v1[0]) == hi);
    A(p1(v1[1]) == gday);
    A(p1(v1[2]) == hello);

     {
      c4_FileStream fs1(fopen("s33b", "wb"), true);
      s1.SaveTo(fs1);
    }

    c4_Storage s2("s33c", 1);

    c4_FileStream fs2(fopen("s33b", "rb"), true);
    s2.LoadFrom(fs2);

    c4_View v2 = s2.View("a");
    A(p1(v2[0]) == hi);
    A(p1(v2[1]) == gday);
    A(p1(v2[2]) == hello);
    s2.Commit();
    A(p1(v2[0]) == hi);
    A(p1(v2[1]) == gday);
    A(p1(v2[2]) == hello);
    s2.Commit();
    A(p1(v2[0]) == hi);
    A(p1(v2[1]) == gday);
    A(p1(v2[2]) == hello);

  }
  D(s33a);
  D(s33b);
  D(s33c);
  R(s33a);
  R(s33b);
  R(s33c);
  E;

  // check smarter commit and commit failure on r/o
  B(s34, Smart and failed commits, 0)W(s34a);
   {
    c4_IntProp p1("p1");
     {
      c4_Storage s1("s34a", 1);
      s1.SetStructure("a[p1:I]");
      c4_View v1 = s1.View("a");
      v1.Add(p1[111]);
      A(v1.GetSize() == 1);
      A(p1(v1[0]) == 111);
      bool f1 = s1.Commit();
      A(f1);
      A(v1.GetSize() == 1);
      A(p1(v1[0]) == 111);
      bool f2 = s1.Commit();
      A(f2); // succeeds, but should not write anything
      A(v1.GetSize() == 1);
      A(p1(v1[0]) == 111);
    }
     {
      c4_Storage s1("s34a", 0);
      c4_View v1 = s1.View("a");
      v1.Add(p1[222]);
      A(v1.GetSize() == 2);
      A(p1(v1[0]) == 111);
      A(p1(v1[1]) == 222);
      bool f1 = s1.Commit();
      A(!f1);
      A(v1.GetSize() == 2);
      A(p1(v1[0]) == 111);
      A(p1(v1[1]) == 222);
    }
  }
  D(s34a);
  R(s34a);
  E;

  B(s35, Datafile with preamble, 0)W(s35a);
   {
     {
      c4_FileStream fs1(fopen("s35a", "wb"), true);
      fs1.Write("abc", 3);
    }
    c4_IntProp p1("p1");
     {
      c4_Storage s1("s35a", 1);
      s1.SetStructure("a[p1:I]");
      c4_View v1 = s1.View("a");
      v1.Add(p1[111]);
      A(v1.GetSize() == 1);
      A(p1(v1[0]) == 111);
      bool f1 = s1.Commit();
      A(f1);
      A(v1.GetSize() == 1);
      A(p1(v1[0]) == 111);
      bool f2 = s1.Commit();
      A(f2); // succeeds, but should not write anything
      A(v1.GetSize() == 1);
      A(p1(v1[0]) == 111);
    }
     {
      c4_FileStream fs1(fopen("s35a", "rb"), true);
      char buffer[10];
      int n1 = fs1.Read(buffer, 3);
      A(n1 == 3);
      A(c4_String(buffer, 3) == "abc");
    }
     {
      c4_Storage s1("s35a", 0);
      c4_View v1 = s1.View("a");
      A(v1.GetSize() == 1);
      A(p1(v1[0]) == 111);
      v1.Add(p1[222]);
      A(v1.GetSize() == 2);
      A(p1(v1[0]) == 111);
      A(p1(v1[1]) == 222);
      bool f1 = s1.Commit();
      A(!f1);
      A(v1.GetSize() == 2);
      A(p1(v1[0]) == 111);
      A(p1(v1[1]) == 222);
    }
  }
  D(s35a);
  R(s35a);
  E;

  B(s36, Commit after load, 0)W(s36a);
  W(s36b);
   {
    c4_IntProp p1("p1");

    c4_Storage s1("s36a", 1);
    s1.SetStructure("a[p1:I]");
    c4_View v1 = s1.View("a");
    v1.Add(p1[111]);
    A(v1.GetSize() == 1);
    A(p1(v1[0]) == 111);

     {
      c4_FileStream fs1(fopen("s36b", "wb"), true);
      s1.SaveTo(fs1);
    }

    p1(v1[0]) = 222;
    v1.Add(p1[333]);
    bool f1 = s1.Commit();
    A(f1);
    A(v1.GetSize() == 2);
    A(p1(v1[0]) == 222);
    A(p1(v1[1]) == 333);

    c4_FileStream fs2(fopen("s36b", "rb"), true);
    s1.LoadFrom(fs2);
    //A(v1.GetSize() == 0); // should be detached, but it's still 2

    c4_View v2 = s1.View("a");
    A(v2.GetSize() == 1);
    A(p1(v2[0]) == 111);

    // this fails in 2.4.0, reported by James Lupo, August 2001
    bool f2 = s1.Commit();
    A(f2);
  }
  D(s36a);
  D(s36b);
  R(s36a);
  R(s36b);
  E;

  // fails in 2.4.1, reported Oct 31. 2001 by Steve Baxter
  B(s37, Change short partial fields, 0)W(s37a);
   {
    c4_BytesProp p1("p1");
    c4_Storage s1("s37a", true);
    c4_View v1 = s1.GetAs("v1[key:I,p1:B]");

    v1.Add(p1[c4_Bytes("12345", 6)]);
    A(v1.GetSize() == 1);
    s1.Commit();

    c4_Bytes buf = p1(v1[0]);
    A(buf.Size() == 6);
    A(buf == c4_Bytes("12345", 6));
    buf = p1(v1[0]).Access(1, 3);
    A(buf == c4_Bytes("234", 3));
    p1(v1[0]).Modify(c4_Bytes("ab", 2), 2, 0);
    s1.Commit();

    buf = p1(v1[0]);
    A(buf == c4_Bytes("12ab5", 6));
  }
  D(s37a);
  R(s37a);
  E;

  // Gross memory use (but no leaks), January 2002, Murat Berk
  B(s38, Lots of empty subviews, 0)W(s38a);
   {
    c4_BytesProp p1("p1");
     {
      c4_Storage s1("s38a", true);
      c4_View v = s1.GetAs("v[v1[p1:S]]");

      v.SetSize(100000);
      s1.Commit();
    }
     {
      c4_Storage s2("s38a", true);
      c4_View v2 = s2.View("v");
      // this should not materialize all the empty subviews
      v2.SetSize(v2.GetSize() + 1);
      // nor should this
      s2.Commit();
    }
     {
      c4_Storage s3("s38a", true);
      c4_View v3 = s3.View("v");
      v3.RemoveAt(1, v3.GetSize() - 2);
      A(v3.GetSize() == 2);
      s3.Commit();
    }
  }
  D(s38a);
  R(s38a);
  E;

  // Fix bug introduced on 7-2-2002, as reported by M. Berk
  B(s39, Do not detach empty top-level views, 0)W(s39a);
   {
    c4_IntProp p1("p1");
    c4_Storage s1("s39a", true);
    c4_View v1 = s1.GetAs("v1[p1:I]");
    s1.Commit();
    A(v1.GetSize() == 0);
    v1.Add(p1[123]);
    A(v1.GetSize() == 1);
    s1.Commit();
    c4_View v2 = s1.View("v1");
    A(v2.GetSize() == 1); // fails with 0 due to recent bug
  }
  D(s39a);
  R(s39a);
  E;
}
Example #13
0
File: persist.cpp Project: aosm/tcl
void c4_SaveContext::SaveIt(c4_HandlerSeq &root_, c4_Allocator **spacePtr_,
  c4_Bytes &rootWalk_) {
  d4_assert(_space != 0);

  const t4_i32 size = _strategy.FileSize();
  if (_strategy._failure != 0)
    return ;

  const t4_i32 end = _fullScan ? 0 : size - _strategy._baseOffset;

  if (_differ == 0) {
    if (_mode != 1)
      _space->Initialize();

    // don't allocate anything inside the file in extend mode
    if (_mode == 2 && end > 0) {
      _space->Occupy(1, end - 1);
      _nextSpace->Occupy(1, end - 1);
    }

    // the header is always reserved
    _space->Occupy(1, 7);
    _nextSpace->Occupy(1, 7);

    if (end > 0) {
      d4_assert(end >= 16);
      _space->Occupy(end - 16, 16);
      _nextSpace->Occupy(end - 16, 16);
      _space->Occupy(end, 8);
      _nextSpace->Occupy(end, 8);
    }
  }

  //AllocDump("a1", false);
  //AllocDump("a2", true);

  // first pass allocates columns and constructs shallow walks
  c4_Column walk(root_.Persist());
  SetWalkBuffer(&walk);
  CommitSequence(root_, true);
  SetWalkBuffer(0);
  CommitColumn(walk);

  c4_Bytes tempWalk;
  walk.FetchBytes(0, walk.ColSize(), tempWalk, true);

  t4_i32 limit = _nextSpace->AllocationLimit();
  d4_assert(limit >= 8 || _differ != 0);

  if (limit < 0) {
    // 2006-01-12 #2: catch file size exceeding 2 Gb
    _strategy._failure =  - 1; // unusual non-zero value flags this case
    return ;
  }

  bool changed = _fullScan || tempWalk != rootWalk_;

  rootWalk_ = c4_Bytes(tempWalk.Contents(), tempWalk.Size(), true);

  _preflight = false;

  // special-case to avoid saving data if file is logically empty
  // in that case, the data is 0x80 0x81 0x80 (plus the header)
  if (!_fullScan && limit <= 11 && _differ == 0) {
    _space->Initialize();
    _nextSpace->Initialize();
    changed = false;
  }

  if (!changed)
    return ;

  //AllocDump("b1", false);
  //AllocDump("b2", true);

  if (_differ != 0) {
    int n = _differ->NewDiffID();
    _differ->CreateDiff(n, walk);
    return ;
  }

  d4_assert(_mode != 0 || _fullScan);

  // this is the place where writing may start

  // figure out where the new file ends and write a skip tail there
  t4_i32 end0 = end;

  // true if the file need not be extended due to internal free space
  bool inPlace = end0 == limit - 8;
  if (inPlace) {
    d4_assert(!_fullScan);
    _space->Release(end0, 8);
    _nextSpace->Release(end0, 8);
    end0 -= 16; // overwrite existing tail markers
  } else {
    /* 18-11-2005 write new end marker and flush it before *anything* else! */
    if (!_fullScan && end0 < limit) {
      c4_FileMark mark1(limit, 0);
      _strategy.DataWrite(limit, &mark1, sizeof mark1);
      _strategy.DataCommit(0);
      if (_strategy._failure != 0)
        return ;
    }

    c4_FileMark head(limit + 16-end, _strategy._bytesFlipped, end > 0);
    _strategy.DataWrite(end, &head, sizeof head);

    if (end0 < limit)
      end0 = limit;
    // create a gap
  }

  t4_i32 end1 = end0 + 8;
  t4_i32 end2 = end1 + 8;

  if (!_fullScan && !inPlace) {
    c4_FileMark mark1(end0, 0);
    _strategy.DataWrite(end0, &mark1, sizeof mark1);
#if q4_WIN32
    /* March 8, 2002
     * On at least NT4 with NTFS, extending a file can cause it to be
     * rounded up further than expected.  To prevent creating a bad
     * file (since the file does then not end with a marker), the
     * workaround it so simply accept the new end instead and rewrite.
     * Note that between these two writes, the file is in a bad state.
     */
    t4_i32 realend = _strategy.FileSize() - _strategy._baseOffset;
    if (realend > end1) {
      end0 = limit = realend - 8;
      end1 = realend;
      end2 = realend + 8;
      c4_FileMark mark1a(end0, 0);
      _strategy.DataWrite(end0, &mark1a, sizeof mark1a);
    }
#endif 
    d4_assert(_strategy.FileSize() == _strategy._baseOffset + end1);
  }

  _space->Occupy(end0, 16);
  _nextSpace->Occupy(end0, 16);

  // strategy.DataCommit(0); // may be needed, need more info on how FS's work
  // but this would need more work, since we can't adjust file-mapping here

  // second pass saves the columns and structure to disk
  CommitSequence(root_, true); // writes changed columns
  CommitColumn(walk);

  //! d4_assert(_curr == 0);
  d4_assert(_nextPosIndex == _newPositions.GetSize());

  if (_fullScan) {
    c4_FileMark mark1(limit, 0);
    _strategy.DataWrite(_strategy.FileSize() - _strategy._baseOffset,  &mark1,
      sizeof mark1);

    c4_FileMark mark2(limit - walk.ColSize(), walk.ColSize());
    _strategy.DataWrite(_strategy.FileSize() - _strategy._baseOffset,  &mark2,
      sizeof mark2);

    return ;
  }

  if (inPlace)
    d4_assert(_strategy.FileSize() == _strategy._baseOffset + end2);
  else {
    // make sure the allocated size hasn't changed
    d4_assert(_nextSpace->AllocationLimit() == limit + 16);
    d4_assert(end0 >= limit);
    d4_assert(_strategy.FileSize() - _strategy._baseOffset == end1);
  }

  if (walk.Position() == 0 || _strategy._failure != 0)
    return ;

  _strategy.DataCommit(0);

  c4_FileMark mark2(walk.Position(), walk.ColSize());
  _strategy.DataWrite(end1, &mark2, sizeof mark2);
  d4_assert(_strategy.FileSize() - _strategy._baseOffset == end2);

  // do not alter the file header in extend mode, unless it is new
  if (!_fullScan && (_mode == 1 || end == 0)) {
    _strategy.DataCommit(0);

    c4_FileMark head(end2, _strategy._bytesFlipped, false);
    d4_assert(head.IsHeader());
    _strategy.DataWrite(0, &head, sizeof head);

    // if the file became smaller, we could shrink it
    if (limit + 16 < end0) {
      /*
      Not yet, this depends on the strategy class being able to truncate, but
      there is no way to find out whether it does (the solution is to write tail
      markers in such a way that the file won't grow unnecessarily if it doesn't).

      The logic will probably be:

       * write new skip + commit "tails" at limit (no visible effect on file)
       * overwrite commit tail at end  with a skip to this new one (equivalent)
       * replace header with one pointing to that internal new one (equivalent)
       * flush (now the file is valid both truncated and not-yet-truncated

      end = limit;
       */
    }
  }

  // if using memory mapped files, make sure the map is no longer in use
  if (_strategy._mapStart != 0)
    root_.UnmappedAll();

  // commit and tell strategy object what the new file size is, this
  // may be smaller now, if old data at the end is no longer referenced
  _strategy.DataCommit(end2);

  d4_assert(_strategy.FileSize() - _strategy._baseOffset == end2);

  if (spacePtr_ != 0 && _space != _nextSpace) {
    d4_assert(*spacePtr_ == _space);
    delete  *spacePtr_;
    *spacePtr_ = _nextSpace;
    _nextSpace = 0;
  }
}