public void Set(string name, string key, RavenJObject data, UuidType uuidType) { Api.JetSetCurrentIndex(session, Lists, "by_name_and_key"); Api.MakeKey(session, Lists, name, Encoding.Unicode, MakeKeyGrbit.NewKey); Api.MakeKey(session, Lists, key, Encoding.Unicode, MakeKeyGrbit.None); var exists = Api.TrySeek(session, Lists, SeekGrbit.SeekEQ); using (var update = new Update(session, Lists, exists ? JET_prep.Replace : JET_prep.Insert)) { Api.SetColumn(session, Lists, tableColumnsCache.ListsColumns["name"], name, Encoding.Unicode); Api.SetColumn(session, Lists, tableColumnsCache.ListsColumns["key"], key, Encoding.Unicode); Api.SetColumn(session, Lists, tableColumnsCache.ListsColumns["etag"], uuidGenerator.CreateSequentialUuid(uuidType).TransformToValueForEsentSorting()); using (var columnStream = new ColumnStream(session, Lists, tableColumnsCache.ListsColumns["data"])) { if (exists) { columnStream.SetLength(0); } using (Stream stream = new BufferedStream(columnStream)) { data.WriteTo(stream); stream.Flush(); } } update.Save(); } }
public Etag AddAttachment(string key, Etag etag, Stream data, RavenJObject headers) { Api.JetSetCurrentIndex(session, Files, "by_name"); Api.MakeKey(session, Files, key, Encoding.Unicode, MakeKeyGrbit.NewKey); var isUpdate = Api.TrySeek(session, Files, SeekGrbit.SeekEQ); if (isUpdate) { var existingEtag = Etag.Parse(Api.RetrieveColumn(session, Files, tableColumnsCache.FilesColumns["etag"])); if (existingEtag != etag && etag != null) { throw new ConcurrencyException("PUT attempted on attachment '" + key + "' using a non current etag") { ActualETag = existingEtag, ExpectedETag = etag }; } } else { if (data == null) throw new InvalidOperationException("When adding new attachment, the attachment data must be specified"); if (Api.TryMoveFirst(session, Details)) Api.EscrowUpdate(session, Details, tableColumnsCache.DetailsColumns["attachment_count"], 1); } Etag newETag = uuidGenerator.CreateSequentialUuid(UuidType.Attachments); using (var update = new Update(session, Files, isUpdate ? JET_prep.Replace : JET_prep.Insert)) { Api.SetColumn(session, Files, tableColumnsCache.FilesColumns["name"], key, Encoding.Unicode); if (data != null) { long written; using (var columnStream = new ColumnStream(session, Files, tableColumnsCache.FilesColumns["data"])) { if (isUpdate) columnStream.SetLength(0); using (var stream = new BufferedStream(columnStream)) { data.CopyTo(stream); written = stream.Position; stream.Flush(); } } if (written == 0) // empty attachment { Api.SetColumn(session, Files, tableColumnsCache.FilesColumns["data"], new byte[0]); } } Api.SetColumn(session, Files, tableColumnsCache.FilesColumns["etag"], newETag.TransformToValueForEsentSorting()); Api.SetColumn(session, Files, tableColumnsCache.FilesColumns["metadata"], headers.ToString(Formatting.None), Encoding.Unicode); update.Save(); } logger.Debug("Adding attachment {0}", key); return newETag; }
public void ShrinkColumnStream() { var bookmark = new byte[SystemParameters.BookmarkMost]; int bookmarkSize; const int Length = 1345; var data = Any.BytesOfLength(Length); using (var transaction = new Transaction(this.sesid)) using (var update = new Update(this.sesid, this.tableid, JET_prep.Insert)) using (var stream = new ColumnStream(this.sesid, this.tableid, this.columnidLongText)) { stream.Write(data, 0, data.Length); stream.Write(data, 0, data.Length); Assert.AreEqual(Length * 2, stream.Length); stream.SetLength(Length); Assert.AreEqual(Length, stream.Length); update.Save(bookmark, bookmark.Length, out bookmarkSize); transaction.Commit(CommitTransactionGrbit.LazyFlush); } Api.JetGotoBookmark(this.sesid, this.tableid, bookmark, bookmarkSize); using (var stream = new ColumnStream(this.sesid, this.tableid, this.columnidLongText)) { Assert.AreEqual(Length, stream.Length); var buffer = new byte[Length]; stream.Read(buffer, 0, buffer.Length); CollectionAssert.AreEqual(data, buffer); } }
public AddDocumentResult InsertDocument(string key, RavenJObject data, RavenJObject metadata, bool checkForUpdates) { var prep = JET_prep.Insert; bool isUpdate = false; if (checkForUpdates) { Api.JetSetCurrentIndex(session, Documents, "by_key"); Api.MakeKey(session, Documents, key, Encoding.Unicode, MakeKeyGrbit.NewKey); isUpdate = Api.TrySeek(session, Documents, SeekGrbit.SeekEQ); if (isUpdate) { prep = JET_prep.Replace; } } using (var update = new Update(session, Documents, prep)) { Api.SetColumn(session, Documents, tableColumnsCache.DocumentsColumns["key"], key, Encoding.Unicode); using (var columnStream = new ColumnStream(session, Documents, tableColumnsCache.DocumentsColumns["data"])) { if (isUpdate) { columnStream.SetLength(0); } using (Stream stream = new BufferedStream(columnStream)) using (var finalStream = documentCodecs.Aggregate(stream, (current, codec) => codec.Encode(key, data, metadata, current))) { data.WriteTo(finalStream); finalStream.Flush(); } } Guid newEtag = uuidGenerator.CreateSequentialUuid(UuidType.Documents); Api.SetColumn(session, Documents, tableColumnsCache.DocumentsColumns["etag"], newEtag.TransformToValueForEsentSorting()); DateTime savedAt = SystemTime.UtcNow; Api.SetColumn(session, Documents, tableColumnsCache.DocumentsColumns["last_modified"], savedAt.ToBinary()); using (var columnStream = new ColumnStream(session, Documents, tableColumnsCache.DocumentsColumns["metadata"])) { if (isUpdate) { columnStream.SetLength(0); } using (Stream stream = new BufferedStream(columnStream)) { metadata.WriteTo(stream); stream.Flush(); } } update.Save(); return(new AddDocumentResult { Etag = newEtag, SavedAt = savedAt, Updated = isUpdate }); } }
public void ColumnStreamSetLengthThrowsExceptionWhenLengthIsNegative() { using (var t = new Transaction(this.sesid)) using (var u = new Update(this.sesid, this.tableid, JET_prep.Insert)) using (var stream = new ColumnStream(this.sesid, this.tableid, this.columnidLongText)) { stream.SetLength(-1); } }
/// <summary>Store the column value in the database.</summary> public override void Serialize(EseCursorBase cur, JET_COLUMNID idColumn, object value, bool bNewRecord) { using (var stm = new ColumnStream(cur.idSession, cur.idTable, idColumn)) { using (XmlDictionaryWriter bw = XmlDictionaryWriter.CreateBinaryWriter(stm, this.dict)) { this.m_serializer.WriteObject(bw, value); bw.Flush(); } // TODO [low]: if the ( current size - new size < 4kb ), then append spaces/zeros instead of resizing the column. The comments inside the SetLength method suggest that shrinking the column is very inefficient for large values. if (stm.Position < stm.Length) { stm.SetLength(stm.Position); } } }
public AddDocumentResult PutDocumentMetadata(string key, RavenJObject metadata) { Api.JetSetCurrentIndex(session, Documents, "by_key"); Api.MakeKey(session, Documents, key, Encoding.Unicode, MakeKeyGrbit.NewKey); var isUpdate = Api.TrySeek(session, Documents, SeekGrbit.SeekEQ); if (isUpdate == false) { throw new InvalidOperationException("Updating document metadata is only valid for existing documents, but " + key + " does not exists"); } Etag newEtag = uuidGenerator.CreateSequentialUuid(UuidType.Documents); DateTime savedAt = SystemTime.UtcNow; using (var update = new Update(session, Documents, JET_prep.Replace)) { Api.SetColumn(session, Documents, tableColumnsCache.DocumentsColumns["etag"], newEtag.TransformToValueForEsentSorting()); Api.SetColumn(session, Documents, tableColumnsCache.DocumentsColumns["last_modified"], savedAt.ToBinary()); using (var columnStream = new ColumnStream(session, Documents, tableColumnsCache.DocumentsColumns["metadata"])) { columnStream.SetLength(0); // always updating here using (Stream stream = new BufferedStream(columnStream)) { metadata.WriteTo(stream); stream.Flush(); } } update.Save(); } return(new AddDocumentResult { Etag = newEtag, SavedAt = savedAt, Updated = true }); }
public void SetColumnStreamToZeroLength() { var bookmark = new byte[SystemParameters.BookmarkMost]; int bookmarkSize; using (var transaction = new Transaction(this.sesid)) using (var update = new Update(this.sesid, this.tableid, JET_prep.Insert)) using (var stream = new ColumnStream(this.sesid, this.tableid, this.columnidLongText)) { byte[] data = Any.Bytes; stream.Write(data, 0, data.Length); stream.SetLength(0); Assert.AreEqual(0, stream.Length); update.Save(bookmark, bookmark.Length, out bookmarkSize); transaction.Commit(CommitTransactionGrbit.LazyFlush); } Api.JetGotoBookmark(this.sesid, this.tableid, bookmark, bookmarkSize); CollectionAssert.AreEqual(new byte[0], Api.RetrieveColumn(this.sesid, this.tableid, this.columnidLongText)); }
public void SetColumnStreamLength() { var bookmark = new byte[SystemParameters.BookmarkMost]; int bookmarkSize; const long Length = 1345; using (var transaction = new Transaction(this.sesid)) using (var update = new Update(this.sesid, this.tableid, JET_prep.Insert)) using (var stream = new ColumnStream(this.sesid, this.tableid, this.columnidLongText)) { stream.SetLength(Length); Assert.AreEqual(Length, stream.Length); update.Save(bookmark, bookmark.Length, out bookmarkSize); transaction.Commit(CommitTransactionGrbit.LazyFlush); } Api.JetGotoBookmark(this.sesid, this.tableid, bookmark, bookmarkSize); using (var stream = new ColumnStream(this.sesid, this.tableid, this.columnidLongText)) { Assert.AreEqual(Length, stream.Length); } }
public AddDocumentResult AddDocument(string key, Etag etag, RavenJObject data, RavenJObject metadata) { if (key == null) { throw new ArgumentNullException("key"); } var byteCount = Encoding.Unicode.GetByteCount(key); if (byteCount >= 2048) { throw new ArgumentException(string.Format("The key must be a maximum of 2,048 bytes in Unicode, 1,024 characters, key is: '{0}'", key), "key"); } try { Api.JetSetCurrentIndex(session, Documents, "by_key"); Api.MakeKey(session, Documents, key, Encoding.Unicode, MakeKeyGrbit.NewKey); var isUpdate = Api.TrySeek(session, Documents, SeekGrbit.SeekEQ); Etag existingEtag = null; if (isUpdate) { existingEtag = EnsureDocumentEtagMatch(key, etag, "PUT"); } else { if (etag != null && etag != Etag.Empty) // expected something to be there. { throw new ConcurrencyException("PUT attempted on document '" + key + "' using a non current etag (document deleted)") { ExpectedETag = etag } } ; if (Api.TryMoveFirst(session, Details)) { Api.EscrowUpdate(session, Details, tableColumnsCache.DetailsColumns["document_count"], 1); } } Etag newEtag = uuidGenerator.CreateSequentialUuid(UuidType.Documents); DateTime savedAt; try { using (var update = new Update(session, Documents, isUpdate ? JET_prep.Replace : JET_prep.Insert)) { Api.SetColumn(session, Documents, tableColumnsCache.DocumentsColumns["key"], key, Encoding.Unicode); using (var columnStream = new ColumnStream(session, Documents, tableColumnsCache.DocumentsColumns["data"])) { if (isUpdate) { columnStream.SetLength(0); // empty the existing value, since we are going to overwrite the entire thing } using (Stream stream = new BufferedStream(columnStream)) using ( var finalStream = documentCodecs.Aggregate(stream, (current, codec) => codec.Encode(key, data, metadata, current)) ) { data.WriteTo(finalStream); finalStream.Flush(); } } Api.SetColumn(session, Documents, tableColumnsCache.DocumentsColumns["etag"], newEtag.TransformToValueForEsentSorting()); savedAt = SystemTime.UtcNow; Api.SetColumn(session, Documents, tableColumnsCache.DocumentsColumns["last_modified"], savedAt.ToBinary()); using (var columnStream = new ColumnStream(session, Documents, tableColumnsCache.DocumentsColumns["metadata"])) { if (isUpdate) { columnStream.SetLength(0); } using (Stream stream = new BufferedStream(columnStream)) { metadata.WriteTo(stream); stream.Flush(); } } update.Save(); } } catch (EsentErrorException e) { if (e.Error == JET_err.KeyDuplicate || e.Error == JET_err.WriteConflict) { throw new ConcurrencyException("PUT attempted on document '" + key + "' concurrently", e); } throw; } logger.Debug("Inserted a new document with key '{0}', update: {1}, ", key, isUpdate); cacher.RemoveCachedDocument(key, newEtag); return(new AddDocumentResult { Etag = newEtag, PrevEtag = existingEtag, SavedAt = savedAt, Updated = isUpdate }); } catch (EsentKeyDuplicateException e) { throw new ConcurrencyException("Illegal duplicate key " + key, e); } }
public AddDocumentResult InsertDocument(string key, RavenJObject data, RavenJObject metadata, bool overwriteExisting) { var prep = JET_prep.Insert; bool isUpdate = false; Etag existingETag = null; if (overwriteExisting) { Api.JetSetCurrentIndex(session, Documents, "by_key"); Api.MakeKey(session, Documents, key, Encoding.Unicode, MakeKeyGrbit.NewKey); isUpdate = Api.TrySeek(session, Documents, SeekGrbit.SeekEQ); if (isUpdate) { existingETag = Etag.Parse(Api.RetrieveColumn(session, Documents, tableColumnsCache.DocumentsColumns["etag"])); prep = JET_prep.Replace; } } try { using (var update = new Update(session, Documents, prep)) { Api.SetColumn(session, Documents, tableColumnsCache.DocumentsColumns["key"], key, Encoding.Unicode); using (var columnStream = new ColumnStream(session, Documents, tableColumnsCache.DocumentsColumns["data"])) { if (isUpdate) { columnStream.SetLength(0); } using (Stream stream = new BufferedStream(columnStream)) using (var finalStream = documentCodecs.Aggregate(stream, (current, codec) => codec.Encode(key, data, metadata, current))) { data.WriteTo(finalStream); finalStream.Flush(); } } Etag newEtag = uuidGenerator.CreateSequentialUuid(UuidType.Documents); Api.SetColumn(session, Documents, tableColumnsCache.DocumentsColumns["etag"], newEtag.TransformToValueForEsentSorting()); DateTime savedAt = SystemTime.UtcNow; Api.SetColumn(session, Documents, tableColumnsCache.DocumentsColumns["last_modified"], savedAt.ToBinary()); using (var columnStream = new ColumnStream(session, Documents, tableColumnsCache.DocumentsColumns["metadata"])) { if (isUpdate) { columnStream.SetLength(0); } using (Stream stream = new BufferedStream(columnStream)) { metadata.WriteTo(stream); stream.Flush(); } } update.Save(); if (existingETag != null) { cacher.RemoveCachedDocument(key, existingETag); } return(new AddDocumentResult { Etag = newEtag, PrevEtag = existingETag, SavedAt = savedAt, Updated = isUpdate }); } } catch (EsentKeyDuplicateException e) { throw new ConcurrencyException("Illegal duplicate key " + key, e); } }
public Guid AddDocumentInTransaction(string key, Guid?etag, RavenJObject data, RavenJObject metadata, TransactionInformation transactionInformation) { Api.JetSetCurrentIndex(session, Documents, "by_key"); Api.MakeKey(session, Documents, key, Encoding.Unicode, MakeKeyGrbit.NewKey); var isUpdate = Api.TrySeek(session, Documents, SeekGrbit.SeekEQ); if (isUpdate) { EnsureNotLockedByTransaction(key, transactionInformation.Id); EnsureDocumentEtagMatchInTransaction(key, etag); using (var update = new Update(session, Documents, JET_prep.Replace)) { Api.SetColumn(session, Documents, tableColumnsCache.DocumentsColumns["locked_by_transaction"], transactionInformation.Id.ToByteArray()); update.Save(); } } else { EnsureDocumentIsNotCreatedInAnotherTransaction(key, transactionInformation.Id); } EnsureTransactionExists(transactionInformation); Guid newEtag = uuidGenerator.CreateSequentialUuid(UuidType.DocumentTransactions); Api.JetSetCurrentIndex(session, DocumentsModifiedByTransactions, "by_key"); Api.MakeKey(session, DocumentsModifiedByTransactions, key, Encoding.Unicode, MakeKeyGrbit.NewKey); var isUpdateInTransaction = Api.TrySeek(session, DocumentsModifiedByTransactions, SeekGrbit.SeekEQ); using (var update = new Update(session, DocumentsModifiedByTransactions, isUpdateInTransaction ? JET_prep.Replace : JET_prep.Insert)) { Api.SetColumn(session, DocumentsModifiedByTransactions, tableColumnsCache.DocumentsModifiedByTransactionsColumns["key"], key, Encoding.Unicode); using (var columnStream = new ColumnStream(session, DocumentsModifiedByTransactions, tableColumnsCache.DocumentsModifiedByTransactionsColumns["data"])) { if (isUpdate) { columnStream.SetLength(0); } using (Stream stream = new BufferedStream(columnStream)) using (var finalStream = documentCodecs.Aggregate(stream, (current, codec) => codec.Encode(key, data, metadata, current))) { data.WriteTo(finalStream); finalStream.Flush(); } } Api.SetColumn(session, DocumentsModifiedByTransactions, tableColumnsCache.DocumentsModifiedByTransactionsColumns["etag"], newEtag.TransformToValueForEsentSorting()); using (var columnStream = new ColumnStream(session, DocumentsModifiedByTransactions, tableColumnsCache.DocumentsModifiedByTransactionsColumns["metadata"])) { if (isUpdate) { columnStream.SetLength(0); } using (Stream stream = new BufferedStream(columnStream)) { metadata.WriteTo(stream); stream.Flush(); } } Api.SetColumn(session, DocumentsModifiedByTransactions, tableColumnsCache.DocumentsModifiedByTransactionsColumns["last_modified"], SystemTime.UtcNow.ToBinary()); Api.SetColumn(session, DocumentsModifiedByTransactions, tableColumnsCache.DocumentsModifiedByTransactionsColumns["delete_document"], false); Api.SetColumn(session, DocumentsModifiedByTransactions, tableColumnsCache.DocumentsModifiedByTransactionsColumns["locked_by_transaction"], transactionInformation.Id.ToByteArray()); update.Save(); } logger.Debug("Inserted a new document with key '{0}', update: {1}, in transaction: {2}", key, isUpdate, transactionInformation.Id); return(newEtag); }